1. Capacités
Pour mieux comprendre les avantages des interfaces et où les utiliser, nous devons parler de choses plus abstraites.
Une classe modélise généralement un objet particulier. Une interface correspond moins aux objets, et plus à leurs capacités ou rôles.
Par exemple, des choses comme les voitures, les vélos, les motos et les roues sont mieux représentées en tant que classes et objets. Mais leurs capacités - telles que "je peux être monté", "je peux transporter des gens", "je peux me tenir debout" - sont mieux présentées comme des interfaces. Voici quelques exemples:
Code | Description |
---|---|
|
Correspond à la capacité de se déplacer |
|
Correspond à l'aptitude à être monté |
|
Correspond à la capacité de transporter des choses |
|
La Wheel classe peut bouger |
|
La Car classe peut se déplacer, être montée et transporter des choses |
|
La Skateboard classe peut bouger et être montée |
2. Rôles
Les interfaces simplifient grandement la vie d'un programmeur. Très souvent, un programme a des milliers d'objets, des centaines de classes, mais seulement quelques dizaines d'interfaces , c'est-à-dire des rôles . Il y a peu de rôles, mais il existe de nombreuses façons de les combiner (classes).
L'intérêt est que vous n'avez pas à écrire de code dans chaque classe pour interagir avec toutes les autres classes. Vous avez juste besoin d'interagir avec leurs rôles (interfaces).
Imaginez que vous êtes un dresseur d'animaux. Chacun des animaux avec lesquels vous travaillez peut avoir plusieurs capacités différentes. Vous vous disputez amicalement avec votre voisin pour savoir quel animal de compagnie peut faire le plus de bruit. Pour régler le problème, il vous suffit d'aligner tous les animaux qui peuvent "parler", et vous leur donnez l'ordre : Parlez !
Vous ne vous souciez pas du genre d'animal qu'ils sont ou de leurs autres capacités. Même s'ils peuvent faire un triple saut périlleux arrière. A ce moment précis, seule leur capacité à parler fort vous intéresse. Voici à quoi cela ressemblerait dans le code :
Code | Description |
---|---|
|
La CanSpeak capacité. Cette interface comprend la commande to speak , ce qui signifie qu'elle a une méthode correspondante. |
|
Les animaux qui ont cette caractéristique.
Pour faciliter la compréhension, nous avons fourni les noms des classes en anglais. Ceci est autorisé en Java, mais il est hautement indésirable.
|
|
Et comment leur donnons-nous la commande ? |
Lorsque le nombre de classes dans vos programmes atteindra les milliers, vous ne pourrez plus vivre sans interfaces. Au lieu de décrire l'interaction de milliers de classes, il suffit de décrire l'interaction de quelques dizaines d'interfaces — cela simplifie grandement la vie.
Et lorsqu'elle est combinée avec le polymorphisme, cette approche est généralement un succès retentissant.
3. La default
mise en œuvre des méthodes d'interface
Les classes abstraites peuvent avoir des variables et des implémentations de méthodes, mais elles ne peuvent pas avoir d'héritage multiple. Les interfaces ne peuvent pas avoir de variables ou d'implémentations de méthodes, mais cela peut avoir plusieurs héritages.
La situation est exprimée dans le tableau suivant :
Capacité/propriété | Cours abstraits | Interfaces |
---|---|---|
variables | ✔ | ✖ |
Mise en œuvre de la méthode | ✔ | ✖ |
Héritage multiple | ✖ | ✔ |
Ainsi, certains programmeurs voulaient vraiment que les interfaces aient la capacité d'avoir des implémentations de méthodes. Mais avoir la possibilité d'ajouter une implémentation de méthode ne signifie pas qu'il en sera toujours ajouté une. Ajoutez-le si vous le souhaitez. Ou si vous ne le faites pas, alors ne le faites pas.
De plus, les problèmes d'héritage multiple sont principalement dus aux variables. En tout cas, c'est ce qu'ils ont décidé et fait. À partir de JDK 8, Java a introduit la possibilité d'ajouter des implémentations de méthode aux interfaces.
Voici un tableau mis à jour (pour JDK 8 et supérieur):
Capacité/propriété | Cours abstraits | Interfaces |
---|---|---|
variables | ✔ | ✖ |
Mise en œuvre de la méthode | ✔ | ✔ |
Héritage multiple | ✖ | ✔ |
Désormais, pour les classes abstraites ainsi que pour les interfaces, vous pouvez déclarer des méthodes avec ou sans implémentation. Et c'est une excellente nouvelle !
Dans les classes abstraites, les méthodes sans implémentation doivent être précédées du abstract
mot clé. Vous n'avez pas besoin d'ajouter quoi que ce soit avant les méthodes avec une implémentation. Dans les interfaces, le contraire est vrai. Si une méthode n'a pas d'implémentation, rien ne doit être ajouté. Mais s'il y a une implémentation, alors le default
mot-clé doit être ajouté.
Pour simplifier, nous présentons ces informations dans le petit tableau suivant :
Capacité/propriété | Cours abstraits | Interfaces |
---|---|---|
Méthodes sans implémentation | abstract |
– |
Méthodes avec une implémentation | – | default |
Problème
L'utilisation d'interfaces dotées de méthodes peut grandement simplifier les grandes hiérarchies de classes. Par exemple, l'abstract InputStream
et OutputStream
les classes peuvent être déclarés comme des interfaces ! Cela nous permet de les utiliser beaucoup plus souvent et beaucoup plus facilement.
Mais il existe déjà des dizaines de millions (milliards ?) de classes Java dans le monde. Et si vous commencez à changer les bibliothèques standard, vous risquez de casser quelque chose. Comme tout! 😛
Afin de ne pas casser accidentellement les programmes et bibliothèques existants, il a été décidé que les implémentations de méthodes dans les interfaces auraient la priorité d'héritage la plus faible .
Par exemple, si une interface hérite d'une autre interface qui a une méthode et que la première interface déclare la même méthode mais sans implémentation, l'implémentation de la méthode à partir de l'interface héritée n'atteindra pas l'interface héritée. Exemple:
interface Pet
{
default void meow()
{
System.out.println("Meow");
}
}
interface Cat extends Pet
{
void meow(); // Here we override the default implementation by omitting an implementation
}
class Tom implements Cat
{
}
Le code ne compilera pas car la Tom
classe n'implémente pas la meow()
méthode.
GO TO FULL VERSION