интерфейс как параметр метода в Java - PullRequest
43 голосов
/ 04 апреля 2010

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

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

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

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

    }
}

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

Ответы [ 8 ]

57 голосов
/ 04 апреля 2010

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

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

24 голосов
/ 04 апреля 2010

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

8 голосов
/ 04 апреля 2010

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

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

6 голосов
/ 04 апреля 2010

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

В псевдо 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

2 голосов
/ 24 января 2018

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

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

1 голос
/ 19 сентября 2016

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

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

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

1 голос
/ 14 февраля 2016

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

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

1 голос
/ 12 апреля 2015

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...