Подтвердить что ты не робот

Интерфейс как параметр метода в Java

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

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

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

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

    }
}

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

В pseudo 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

Ответ 5

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

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

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

Ответ 6

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

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

Ответ 7

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

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

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