J'ai cette interface:
public interface Animal {
public void Eat(String name);
}
Et ce code implémente ici l'interface:
public class Dog implements Animal {
public void Eat(String food_name) {
System.out.printf(food_name);
}
public static void main(String args[]) {
Animal baby2 = new Dog(); //HERE!!!!!!!!!!!!!!!!!!!!!!
baby2.Eat("Meat");
}
}
Ma question est, pourquoi le code fonctionne-t-il? Une interface ne peut pas être instanciée. Pourtant dans ce cas, l'interface a été instanciée (marquée avec le commentaire "ICI !!!!!!!!!!!!").
Que se passe-t-il ici?
Non, ce n'est pas le cas - vous instanciez une Dog
, mais comme Dog
est une Animal
, vous pouvez déclarer la variable comme étant une Animal
. Si vous essayez d’instancier l’interface Animal
, ce sera:
Animal baby2 = new Animal();
Essayez cela et regardez le compilateur hurler d'horreur :)
Dog
n'est pas une interface: Dog
est une classe que implémente l'interface Animal
.
Il n’ya rien de fâcheux ici.
Notez que vous pouvez instancier une implémentation anonyme d'une interface, comme ceci:
Animal animal = new Animal() {
public void Eat(String food_name) {
System.out.printf("Someone ate " + food_name);
}
};
Considérons le code ci-dessous:
interface Cookable {
public void cook();
}
class Food {
Cookable c = new Cookable() {
public void cook() {
System.out.println("anonymous cookable implementer");
}
};
}
Le code précédent crée une instance d'une classe interne anonymous, mais ici, la nouvelle classe just-in-time est un implémenteur de l'interface Cookable. Et notez que c’est le seul moment où vous verrez la syntaxe:
new Cookable()
où Cookable est une interface plutôt qu'un type de classe non abstraite. Pensez-y: Vous ne pouvez pas instancier une interface, mais c'est ce à quoi ressemble le code. Mais, bien sûr, il ne s'agit pas d'instancier un Cookable object
--, il crée une instance d'un nouveau anonymous implementer of Cookable
.
Vous pouvez lire cette ligne:
Cookable c = new Cookable(){}
comme "Déclarer une variable de référence de type Cookable qui, évidemment, fera référence à un objet d'une classe qui implémente l'interface Cookable. Mais, oh oui, nous n'avons pas encore une classe qui implémente Cookable, nous allons donc en créer un ici, pour le moment. Nous n'avons pas besoin d'un nom pour la classe, mais ce sera une classe qui implémentera Cookable., et cette accolade lance la définition de la nouvelle classe d'implémentation. "
Important à retenir pour les implémenteurs d'interface anonyme: ils ne peuvent implémenter qu'une seule interface. Il n'y a tout simplement aucun mécanisme pour dire que votre classe interne anonyme va implémenter plusieurs interfaces. En fait, une classe interne anonyme ne peut même pas étendre une classe et implémenter une interface en même temps. La classe innve doit choisir d'être une sous-classe d'une classe nommée et de ne pas implémenter directement d'interface ou d'implémenter une interface unique.
Donc, ne vous laissez pas avoir par aucune tentative d'instancier une interface, sauf dans le cas d'une classe interne anonyme. Ce qui suit n'est pas légal:
Runnable r = new Runnable(); // can't instantiate interface
alors que ce qui suit est légal, car il instancie un implémenteur de l'interface Runnable (une classe d'implémentation anonyme):
Runnable r = new Runnable() {
public void run(){ }
};
Vous pouvez lire mon article ici .
Vous observez ici l’aspect inversion de dépendance de SOLIDE .
Votre code dépend de l'abstraction du contrat Animal
en instanciant une implémentation concrète de celui-ci. Vous dites simplement: "J'installe un objet, mais quel que soit l'objet est réellement, il sera lié au contrat de l'interface Animal
."
Prenons, par exemple, ces sortes de déclarations:
List<String> wordList = new LinkedList<>();
Map<Integer, String> mapping = new HashMap<>();
Dans ces deux cas, le principal aspect de la liste et de la carte est qu'ils suivent le contrat générique pour List
et Map
.
Animal baby2 = new Dog(); //HERE!!!!!!!!!!!!!!!!!!!!!!
Vous n'êtes sûrement pas en train d'instancier l'animal. Vous ne faites que renvoyer l'instance de Dog à celle-ci . En Java, nous pouvons prendre la référence de la super classe.
Quand tu dis:
Animal baby2 = new Dog();
le type de référence est Animal (l'interface), qui pointe vers une implémentation concrète (Dog). Le type d'objet Chien est concret et peut être instancié. Dans ce cas, tant que Chien a un point animal sur Chien. une implémentation concrète de toutes les méthodes de l'interface, vous pouvez créer un type de référence
Si vous avez fait quelque chose comme,
Animal baby2 = new Animal(); // here you are actually instantiating
cela ne serait pas valide car vous essayez maintenant de créer un objet concret à partir d'une implémentation abstraite.
Pour avoir une image plus large:
Animal [] Zoo = new Animal[10] ; // is also correct
mais pourquoi ?
L'idée est que dans le tableau ci-dessus, vous pouvez placer 10 animaux de types différents. La seule condition à cela est que tous les animaux entrant dans le zoo doivent implémenter l'interface Animal.
public interface Animal {
void Eat();
}
class Wolf implements Animal { void Eat (){
System.out.println("Wolf eats meat ") ;}}
Class Zebra implements Animal{ void Eat (){
System.out.println("Zebra eats the grass ") ;}}
class test {
public static void main (String args []) {
Animal [] Zoo = new Animal[2] ;
Zoo[0] = new Wolf() ;
Zoo[1] = new Zebra() ;
//so you can feed your animals in Zoo like this
for (int i=0 ; i<Zoo.lenght;i++) {Zoo[i].Eat();}
}
}
Ceci est un cas de polymorphisme, on dirait que vous créez un objet 'Animal' mais ce n'est pas le cas. Vous créez un objet 'Chien' qui est calculé au moment de l'exécution. 'Animal' agit comme un contrat. L’interface ne peut pas être instanciée directement mais peut être utilisée comme type en effectuant une conversion ascendante de sa sous-classe. Vous pouvez également utiliser une classe anonyme pour instancier un objet en tant que type 'Animal'.
Animal baby2 = new Dog(); //upcasting polymorphically
Animal baby3=new Animal(){
public void Eat(String food){System.out.println("fdkfdfk"); }
}
//You can instantiate directly as anonymous class by implementing all the method of interface
L'interface animal agit comme type de données pour la classe Dog. En fait, vous instanciez la classe Dog et non l'interface ou son type de données.
L'interface Animal
n'est pas instanciée mais implémentée par Dog
. Et une Dog
est intantiée
En fait, vous pouvez instancier l'interface. Voici le code que vous pouvez essayer
public static void main(String args[]) {
System.out.println(new Animal() {
public String toString() {
return "test";
}
});
}
Ce programme s'exécute avec succès et affiche test
Essayez-le.
Ici, il ne s’agit que de faire référence à l’interface, mais l’instanciation est effectuée uniquement par la classe ..
Animanl a = new Dog Animal a - la variable est référencéenew Dog - now