interface en tant que paramètre de méthode en Java
J'ai eu une interview il y a quelques jours et on m'a posé une question comme celle-ci.
Q: Inverser une liste liée. Code suivant est donné:
public class ReverseList {
interface NodeList {
int getItem();
NodeList nextNode();
}
void reverse(NodeList node) {
}
public static void main(String[] args) {
}
}
J'étais confus parce que je ne savais pas qu'un objet d'interface pouvait être utilisé comme paramètre de méthode. L'intervieweur a expliqué un peu mais je ne suis toujours pas sûr à ce sujet. Quelqu'un pourrait m'éclairer?
8 réponses
C'est en fait l'une des plus courantes et les plus utiles manières d'utiliser une interface. L'interface définit un contrat, et votre code peut fonctionner avec n'importe quelle classe qui implémente l'interface, sans avoir à connaître la classe concrète - il peut même fonctionner avec des classes qui n'existaient pas encore lorsque le code a été écrit.
Il existe de nombreux exemples dans L'API Java standard, en particulier dans le framework collections. Par exemple, Collections.sort () peut trier tout ce qui implémente le List
interface (pas seulement ArrayList
ou LinkedList
, bien que l'implémentation de votre propre List
soit rare) et dont le contenu implémente l'interface Comparable
(pas seulement String
ou les classes wrapper numériques-et avoir votre propre classe implémenter Comparable
à cette fin est assez commun).
Ce n'est pas l'interface "objet" qui est passée à la méthode, mais juste un objet normal. C'est juste une façon de dire "ce paramètre acceptera tout objet qui supporte cette interface". Cela équivaut à accepter un objet d'un type de classe de base, même si vous passez une sous-classe.
C'est ce qu'on appelle la programmation aux interfaces. Vous ne codez pas sur une classe d'implémentation spécifique de listes de nœuds mais sur l'interface implémentée par toutes ces implémentations.
De cette façon, votre code fonctionnera toujours si quelqu'un écrit une nouvelle et bien meilleure implémentation de NodeList
après avoir écrit votre méthode inverse et vous n'avez pas à adapter votre code pour chaque nouvelle implémentation de NodeList
.
L'argument a besoin d'un objet dont la classe implémente une interface (le paramètre).
Dans pseudo - Java le code:
void reverse(NodeList node) {
// your code
}
Est égal à:
reverse(x) {
if(x == null || x instanceof NodeList) {
// your code
}else throw new RuntimeException("Some sort of error.");
}
Note; En savoir plus sur les Interfaces ici: http://java.sun.com/docs/books/tutorial/java/IandI/interfaceAsType.html
Avait cette même confusion en apprenant des trucs lambda. Cette vidéo n'a pas expliqué le concept, mais c'est un moyen clair pour vous de voir comment cela fonctionne en termes de passage d'une interface en tant que paramètre.
Le principal avantage de l'utilisation des interfaces, à mon humble avis, est de pouvoir tester facilement. Supposons que vous ayez une interface appelée PatientManager.
Vous pouvez écrire des tests unitaires spécifiques pour des choses imaginables comme "CachingPatientManager" ou "LDAPPatientManager", le cas d'utilisation pourrait être myriad.
L'avantage est que la programmation À l'interface devient hautement réutilisable et testable.
Vous ne pouvez pas créer une instance (objet ) d'une Interface. Oui, vous pouvez passer L'Interface en tant que paramètre dans la fonction. Mais la question semble incomplète. L'Interface n'est implémentée par aucune classe. Il manque quelque chose. Si vous essayez d'exécuter ceci, le compilateur ne montrera aucune erreur.
Mais, dans la méthode reverse (), vous devez créer une instance de classe qui implémente l'interface NodeList. J'espère que cela a du sens.
C'est une implémentation possible:
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());
}
}
Sortie du programme:
Before reversal
1->2->3->null
After reversal
3->2->1->null
Je suis très curieux de savoir si ce problème peut être résolu en utilisant une classe anonyme. Des idées?