Интерфейс как параметр метода в Java
У меня было интервью несколько дней назад, и мне задали такой вопрос.
Q: Обратный список. Предоставляется следующий код:
public class ReverseList {
interface NodeList {
int getItem();
NodeList nextNode();
}
void reverse(NodeList node) {
}
public static void main(String[] args) {
}
}
Я был сбит с толку, потому что я не знал, что объект интерфейса может использоваться как параметр метода. Интервьюер объяснил немного, но я до сих пор не уверен в этом. Может ли кто-нибудь просветить меня?
Ответы
Ответ 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
Мне очень любопытно узнать, можно ли решить эту проблему с помощью анонимного класса. Любые идеи?