2010-04-04 15 views
32

Tuve una entrevista días atrás y se formuló una pregunta como esta.interfaz como un parámetro de método en Java

P: Invierta una lista vinculada. El siguiente código se da:

public class ReverseList { 
    interface NodeList { 
     int getItem(); 
     NodeList nextNode(); 
    } 
    void reverse(NodeList node) { 

    } 
    public static void main(String[] args) { 

    } 
} 

Estaba confundido porque no sabía que un objeto de interfaz podría usarse como un parámetro de método. El entrevistador explicó un poco, pero todavía no estoy seguro de esto. ¿Alguien podría iluminarme?

Respuesta

52

Esta es, de hecho, una de las formas más comunes y útiles de utilizar una interfaz. La interfaz define un contrato, y su código puede funcionar con cualquier clase que implemente la interfaz, sin tener que conocer la clase concreta, incluso puede funcionar con clases que aún no existían cuando se escribió el código.

Hay muchos ejemplos en la API estándar de Java, especialmente en el marco de colecciones. Por ejemplo, Collections.sort() puede ordenar cualquier cosa que implementa la interfaz List (no sólo ArrayList o LinkedList, aunque la implementación de su propia List es raro) y cuyo contenido implementar la interfaz Comparable (no sólo String o las clases de envoltura numéricos - y tener su propia clase implemente Comparable para ese propósito es bastante común).

+0

Gracias Mike! El ejemplo de lista es realmente instructivo y fácil de entender. – zihaoyu

6

El argumento necesita un objeto, cuya clase implementa una interfaz (el parámetro).

En seudo el código de Java:

void reverse(NodeList node) { 
    // your code 
} 

es igual a:

reverse(x) { 
    if(x == null || x instanceof NodeList) { 
     // your code 
    }else throw new RuntimeException("Some sort of error."); 
} 

Nota; lea más en Interfaces aquí: http://java.sun.com/docs/books/tutorial/java/IandI/interfaceAsType.html

+8

El parámetro * * es un tipo de interfaz, el argumento * * es un objeto skaffman

+3

Y para ser realmente mucho un pedent. El argumento es una referencia a un objeto:} –

+0

+1 para el enlace tutorial convincente. – trashgod

19

No es la interfaz "objeto" que se pasa al método, sigue siendo solo un objeto normal. Es solo una forma de decir "este parámetro aceptará cualquier objeto que admita esta interfaz". Es equivalente a aceptar algún objeto de un tipo de clase base, incluso si está pasando en una subclase.

+0

Genial, ayudado !! : D – roottraveller

7

Esto se denomina programación de interfaces. No codifica a una clase de implementación específica de listas de nodos sino a la interfaz implementada por todas esas implementaciones.

De esta forma, su código seguirá funcionando si alguien escribe una nueva y mejor implementación de NodeList después de escribir su método inverso y no tiene que adaptar su código para cada nueva implementación de NodeList.

1

El principal beneficio de utilizar interfaces, en mi humilde opinión, es que se puede probar fácilmente. Supongamos que tiene una interfaz llamada PatientManager.

Puede escribir pruebas de unidades específicas para cosas imaginables como "CachingPatientManager" o "LDAPPatientManager", el caso de uso podría ser innumerable.

La ventaja es que la programación de la interfaz se vuelve altamente reutilizable y comprobable.

1

No puede crear una instancia (/ objeto) de una interfaz. Sí, puede pasar Interface como parámetro en la función. Pero la pregunta parece incompleta.La interfaz no está implementada por ninguna clase. Algo falta. Si intenta ejecutar esto, el compilador no mostrará ningún error.

Pero, en el método reverse(), necesita crear una instancia de clase que implemente la interfaz NodeList. Espero que esto tenga sentido.

0

Ésta es una posible implementación:

public class ReverseList { 
interface NodeList { 
    int getItem(); 
    NodeList nextNode(); 
} 

static class Node implements NodeList { 
    private int item; 
    private Node next; 

    @Override 
    public int getItem() { 
     return item; 
    } 

    public void setItem(int si) { 
     item = si; 
    } 

    @Override 
    public NodeList nextNode() { 
     return this.next; 
    } 

    public void setNext(Node n) {this.next=n;} 

} 

Node reverse(NodeList head) { 
    Node node = (Node) head; 
    Node previous = null; 
    while(node.nextNode() !=null) { 
     Node tempNext = (Node) node.nextNode(); 
     node.setNext(previous); 
     previous = node; 
     node = tempNext; 
    } 
    node.setNext(previous); 
    return node; 

} 
public static void main(String[] args) { 
    //Initialization block 
    ReverseList rl = new ReverseList(); 
    Node n1= new Node(); n1.setItem(1); 
    Node n2=new Node(); n2.setItem(2); 
    Node n3 =new Node(); n3.setItem(3); 
    n1.setNext(n2); n2.setNext(n3); n3.setNext(null); 

    //Reversing the list 
    System.out.println("Before reversal");  
    System.out.println(n1.getItem() +"->" 
        + n1.nextNode().getItem() + "->" 
        + n1.nextNode().nextNode().getItem() + "->" 
        +n1.nextNode().nextNode().nextNode()); 


    rl.reverse(n1); 

    System.out.println("\nAfter reversal"); 
    System.out.println(n3.getItem() +"->" 
      + n3.nextNode().getItem() + "->" 
      + n3.nextNode().nextNode().getItem() + "->" 
      +n3.nextNode().nextNode().nextNode()); 
     } 
} 

La salida del programa:

Before reversal 
1->2->3->null 

After reversal 
3->2->1->null 

Estoy muy curioso por saber si este problema puede ser resuelto mediante el uso de una clase anónima. ¿Algunas ideas?

0

Tuve esta misma confusión mientras aprendía cosas lambda. Este video no explicó el concepto, pero es una forma clara de ver cómo funciona en términos de pasar una interfaz como parámetro.

https://www.youtube.com/watch?v=mk3erzL70yM

Cuestiones relacionadas