2010-04-04 3 views
32

У меня было интервью дней назад, и мне задали такой вопрос.интерфейс как параметр метода в Java

В: Обратный список связанных. Приводится следующий код:

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

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

    } 
} 

Я был смущен, потому что не знал, что объект интерфейса может использоваться как параметр метода. Интервьюер объяснил немного, но я до сих пор не уверен в этом. Может ли кто-нибудь просветить меня?

ответ

52

Это на самом деле один из наиболее распространенных и полезных способов использования интерфейса. Интерфейс определяет контракт, и ваш код может работать с любым классом, который реализует интерфейс, без необходимости знать конкретный класс - он может даже работать с классами, которые еще не существовали при написании кода.

В стандартном API Java много примеров, особенно в рамках коллекций. Например, Collections.sort() сортировать все, что реализует интерфейс List (а не только ArrayList или LinkedList, хотя реализовать ваши собственные List редко), и содержание которого реализуют интерфейс Comparable (а не только String или числовые классы-оболочки - и иметь свой собственный класс реализации Comparable для этой цели совершенно общий).

+0

Спасибо, Майк! Пример списка действительно поучителен и понятен. – zihaoyu

6

Аргумент нуждается в объекте, класс которого реализует интерфейс (параметр).

В псевдо Java код:

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

равно:

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

Примечание; подробнее здесь. Интерфейсы здесь: http://java.sun.com/docs/books/tutorial/java/IandI/interfaceAsType.html

+8

Символ * Параметр * является типом интерфейса, * * аргумент является объектом skaffman

+3

И быть действительно степени pedent. Аргумент является ссылкой на объект:} –

+0

+1 для ссылки cogent tutorial. – trashgod

19

Это не интерфейс «объект», передаваемый методу, все еще только обычный объект. Это всего лишь способ сказать, что «этот параметр примет любой объект, который поддерживает этот интерфейс». Это эквивалентно принятию некоторого объекта типа базового класса, даже если вы проходите в подклассе.

+0

Отлично, помогли! : D – roottraveller

7

Это называется программированием для интерфейсов. Вы не кодируете конкретный класс реализации списков узлов, а интерфейс, реализованный всеми этими реализациями.

Таким образом, ваш код будет работать, если кто-то пишет новую и намного лучшую реализацию NodeList после того, как вы написали обратный метод, и вам не нужно адаптировать свой код для каждой новой реализации NodeList.

1

Главное преимущество использования интерфейсов, IMHO, позволяет легко протестировать. Предположим, у вас есть интерфейс под названием PatientManager.

Вы можете написать конкретные модульные тесты для таких мыслимых вещей, как «CachingPatientManager» или «LDAPPatientManager», прецедент может быть несметным.

Преимущество в том, что программирование для интерфейса становится очень многоразовым и проверяемым.

1

Вы не можете создать экземпляр (/ объект) интерфейса. Да, вы можете передать интерфейс в качестве параметра в функции. Но вопрос кажется неполным.Интерфейс не реализуется ни одним классом. Чего-то не хватает. Если вы попытаетесь запустить это, компилятор не будет показывать никаких ошибок.

Но в обратном() методе необходимо создать экземпляр класса, который реализует интерфейс NodeList. Я надеюсь в этом есть смысл.

0

Это одна из возможных реализаций:

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

выход программы:

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

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

Мне очень интересно знать, если эта проблема может быть решена с помощью анонимного класса. Есть идеи?

0

Было такое же замешательство во время изучения материала лямбды. Это видео не объясняло концепцию, но это четкий способ увидеть, как он работает с точки зрения передачи интерфейса в качестве параметра.

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

Смежные вопросы