2010-04-04 5 views
32

Miałem wywiad kilka dni temu i zadano mi takie pytanie.Interfejs jako parametr metody w Javie

P: Odwróć połączoną listę. Poniższy kod jest podany:

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

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

    } 
} 

Byłem zdezorientowany, ponieważ nie wiedziałem, że obiekt interfejsu może być używany jako parametr metody. Wywiad wyjaśnił mi trochę, ale nadal nie jestem tego pewien. Czy ktoś mógłby mnie oświecić?

Odpowiedz

52

Jest to jeden z najbardziej powszechnych i użytecznych sposobów korzystania z interfejsu. Interfejs definiuje kontrakt, a twój kod może współpracować z dowolną klasą, która implementuje interfejs, bez znajomości konkretnej klasy - może nawet pracować z klasami, które jeszcze nie istniały, gdy kod został napisany.

Istnieje wiele przykładów w standardowym interfejsie API języka Java, zwłaszcza w ramach kolekcji. Na przykład, Collections.sort() można sortować niczego, która implementuje interfejs List (nie tylko ArrayList lub LinkedList, choć wdrażaniu własnych List jest rzadkością) i którego zawartość implementować interfejs Comparable (nie tylko String lub numerycznych klasy otoki - i posiadające własne klasy wdrożenia Comparable w tym celu jest dość wspólny).

+0

Dzięki Mike! Przykład listy jest naprawdę pouczający i łatwy do zrozumienia. – zihaoyu

6

Argument wymaga obiektu, którego klasa implementuje interfejs (parametr).

W pseudo Java kod:

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

jest równa:

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

nocie; Przeczytaj więcej o interfejsach tutaj: http://java.sun.com/docs/books/tutorial/java/IandI/interfaceAsType.html

+8

Gwiazdka * * parametr jest typ interfejsu, i * * argumentem jest obiektem skaffman

+3

I być naprawdę dużo pedent. Argument jest odniesieniem do obiektu:} –

+0

+1 dla przekonującego linku samouczka. – trashgod

19

Nie jest to "obiekt" interfejsu przekazywany do metody, a jedynie zwykły obiekt. To tylko sposób powiedzenia "ten parametr zaakceptuje dowolny obiekt obsługujący ten interfejs". Jest to równoważne z zaakceptowaniem jakiegoś obiektu klasy bazowej, nawet jeśli przechodzisz do podklasy.

+0

Świetnie, pomogło !! : D – roottraveller

7

Nazywa się to programowaniem do interfejsów. Nie kodujesz konkretnej klasy implementacji list węzłów, ale interfejs implementowany przez wszystkie te implementacje.

W ten sposób Twój kod będzie nadal działał, jeśli ktoś napisze nową i znacznie lepszą implementację NodeList po napisaniu swojej metody odwrotnej i nie musisz dostosowywać swojego kodu do każdej nowej implementacji NodeList.

1

Główna zaleta korzystania z interfejsów, IMHO, jest łatwa do przetestowania. Załóżmy, że masz interfejs o nazwie PatientManager.

Możesz pisać konkretne testy jednostkowe dla wyobrażalnych rzeczy, takich jak "CachingPatientManager" lub "LDAPPatientManager", przypadek użycia może być niezliczony.

Korzyścią jest to, że programowanie w interfejsie staje się wysoce wielokrotnego użytku i testowalne.

1

Nie można utworzyć instancji (/ obiektu) interfejsu. Tak, możesz przekazać interfejs jako parametr w funkcji. Ale pytanie wydaje się niepełne.Interfejs nie jest implementowany przez żadną klasę. Coś brakuje. Jeśli spróbujesz to uruchomić, kompilator nie pokaże żadnego błędu.

Ale w odwrotnej() metodzie trzeba utworzyć instancję klasy, która implementuje interfejs NodeList. Mam nadzieję, że to ma sens.

0

Jest to jedno z możliwych rozwiązań:

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()); 
     } 
} 

wyjście Program:

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

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

Jestem bardzo ciekaw, czy ten problem może być rozwiązany za pomocą anonimowej klasy. Jakieś pomysły?

0

Mieliśmy to samo zamieszanie, ucząc się rzeczy lambdy. Ten film nie wyjaśnił pojęcia, ale jest to jasny sposób, aby zobaczyć, jak działa pod względem przekazywania interfejsu jako parametru.

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