JavaRush /Blog Java /Random-FR /Méthodes par défaut dans Java 8 : que peuvent-elles et ne...
Spitfire
Niveau 33

Méthodes par défaut dans Java 8 : que peuvent-elles et ne peuvent-elles pas faire ?

Publié dans le groupe Random-FR
Traduction d' un article rédigé par Peter Verhas en avril 2014. Méthodes par défaut dans Java 8 : que peuvent-elles et ne peuvent-elles pas faire ?  - 1Du traducteur : le terme « méthode par défaut » vient d'apparaître en Java et je ne sais pas s'il existe une traduction établie en russe pour cela. J'utiliserai le terme « méthode par défaut », même si je ne pense pas que ce soit idéal. Je vous invite à discuter d’une traduction plus réussie.

Quelle est la méthode par défaut

Désormais, avec la sortie de Java 8, vous pouvez ajouter de nouvelles méthodes aux interfaces afin que l'interface reste compatible avec les classes qui l'implémentent. Ceci est très important si vous développez une bibliothèque utilisée par de nombreux programmeurs de Kiev à New York. Avant Java 8, si vous définissiez une interface dans une bibliothèque, vous ne pouviez pas y ajouter de méthodes sans risquer qu'une application exécutant votre interface se brise lors de sa mise à jour. Alors, en Java 8, vous ne pouvez plus avoir peur de ça ? Non tu ne peux pas. L'ajout d'une méthode par défaut à une interface peut rendre certaines classes inutilisables. Examinons d'abord les avantages des méthodes par défaut. En Java 8, la méthode peut être implémentée directement dans l'interface. (Les méthodes statiques dans une interface peuvent désormais également être implémentées, mais c'est une autre histoire.) Une méthode implémentée dans une interface est appelée méthode par défaut et est désignée par le mot-clé default . Si une classe implémente une interface, elle peut, mais ce n'est pas obligatoire, implémenter les méthodes implémentées dans l'interface. La classe hérite de l'implémentation par défaut. C'est pourquoi il n'est pas nécessaire de modifier les classes lors du changement de l'interface qu'elles implémentent.

Héritage multiple ?

Les choses deviennent plus compliquées si une classe implémente plus d’une (disons, deux) interfaces et qu’elles implémentent la même méthode par défaut. De quelle méthode la classe héritera-t-elle ? La réponse est aucune. Dans ce cas, la classe doit implémenter elle-même la méthode (soit directement, soit en héritant d'une autre classe). La situation est similaire si une seule interface a une méthode par défaut et que dans l'autre, la même méthode est abstraite. Java 8 essaie d'être discipliné et d'éviter les situations ambiguës. Si les méthodes sont déclarées dans plusieurs interfaces, alors aucune implémentation par défaut n'est héritée par la classe - vous obtiendrez une erreur de compilation. Cependant, vous n'obtiendrez peut-être pas d'erreur de compilation si votre classe est déjà compilée. Java 8 n'est pas assez robuste à cet égard. Il y a des raisons à cela, que je ne veux pas aborder (par exemple : la version Java est déjà sortie et le temps des discussions est révolu depuis longtemps et en général, ce n'est pas le lieu pour elles).
  • Disons que vous disposez de deux interfaces et qu’une classe les implémente toutes les deux.
  • L'une des interfaces implémente la méthode par défaut m().
  • Vous compilez toutes les interfaces et la classe.
  • Vous modifiez une interface qui n’a pas de méthode m() en la déclarant comme méthode abstraite.
  • Vous compilez uniquement l'interface modifiée.
  • Commencez le cours.
Méthodes par défaut dans Java 8 : que peuvent-elles et ne peuvent-elles pas faire ?  - 2Dans ce cas, la classe fonctionne. Vous ne pouvez pas le compiler avec les interfaces mises à jour, mais il a été compilé avec des versions plus anciennes et fonctionne donc. Maintenant
  • changez l'interface avec la méthode abstraite m() et ajoutez une implémentation par défaut.
  • Compilez l'interface modifiée.
  • Exécuter la classe : erreur.
Lorsqu'il existe deux interfaces qui fournissent une implémentation par défaut d'une méthode, cette méthode ne peut pas être appelée dans une classe à moins qu'elle ne soit implémentée par la classe elle-même (encore une fois, seule ou héritée d'une autre classe). Méthodes par défaut dans Java 8 : que peuvent-elles et ne peuvent-elles pas faire ?  - 3Compatible classe. Il peut être chargé avec une interface modifiée. Il peut même s'exécuter jusqu'à l'appel d'une méthode ayant une implémentation par défaut dans les deux interfaces.

Exemple de code

Méthodes par défaut dans Java 8 : que peuvent-elles et ne peuvent-elles pas faire ?  - 4Pour démontrer ce qui précède, j'ai créé un répertoire de test pour la classe C.java et 3 sous-répertoires pour les interfaces dans les fichiers I1.java et I2.java. Le répertoire racine du test contient le code source de la classe C.java. Le répertoire de base contient une version des interfaces adaptée à l'exécution et à la compilation : l'interface I1 a une méthode par défaut m(); L'interface I2 ne dispose pas encore de méthodes. La classe a une méthode mainafin que nous puissions l'exécuter pour la tester. Il vérifie s'il existe des arguments de ligne de commande, nous pouvons donc facilement l'exécuter avec ou sans appeler le m().
~/github/test$ cat C.java
public class C implements I1, I2 {
  public static void main(String[] args) {
    C c = new C();
    if( args.length == 0 ){
      c.m();
    }
  }
}
~/github/test$ cat base/I1.java
public interface I1 {
  default void m(){
    System.out.println("hello interface 1");
  }
}
~/github/test$ cat base/I2.java
public interface I2 {
}
Vous pouvez compiler et exécuter la classe à partir de la ligne de commande.
~/github/test$ javac -cp .:base C.java
~/github/test$ java -cp .:base C
hello interface 1
Le répertoire compatible contient une version de l'interface I2 qui déclare la méthode m() comme abstraite, ainsi que, pour des raisons techniques, une copie non modifiée de I1.java.
~/github/test$ cat compatible/I2.java

public interface I2 {
  void m();
}
Un tel ensemble ne peut pas être utilisé pour compiler une classe C :
~/github/test$ javac -cp .:compatible C.java
C.java:1: error: C is not abstract and does not override abstract method m() in I2
public class C implements I1, I2 {
       ^
1 error
Le message d'erreur est très précis. Cependant, nous avons C.class d'une compilation précédente et, si nous compilons les interfaces dans le répertoire compatible, nous aurons deux interfaces qui pourront toujours être utilisées pour exécuter la classe :
~/github/test$ javac compatible/I*.java
~/github/test$ java -cp .:compatible C
hello interface 1
Le troisième répertoire - wrong- contient la version I2, qui déclare également la méthode m():
~/github/test$ cat wrong/I2.java
public interface I2 {
  default void m(){
    System.out.println("hello interface 2");
  }
}
Vous n'avez même pas à vous soucier de la compilation. Même si la méthode est déclarée deux fois, la classe peut toujours être utilisée et exécutée jusqu'à ce que la méthode m() soit appelée. C'est pour cela que nous avons besoin de l'argument de ligne de commande :
~/github/test$ javac wrong/*.java
~/github/test$ java -cp .:wrong C
Exception in thread "main" java.lang.IncompatibleClassChangeError: Conflicting default methods: I1.m I2.m
    at C.m(C.java)
    at C.main(C.java:5)
~/github/test$ java -cp .:wrong C x
~/github/test$

Conclusion

Lorsque vous porterez votre bibliothèque vers Java 8 et modifierez vos interfaces pour inclure les méthodes par défaut, vous n'aurez probablement aucun problème. C'est du moins ce qu'espèrent les développeurs de bibliothèques Java 8 en ajoutant des fonctionnalités. Les applications utilisant votre bibliothèque l'utilisent toujours pour Java 7, où il n'existe pas de méthodes par défaut. Si plusieurs bibliothèques sont utilisées ensemble, il existe un risque de conflit. Comment l'éviter ? Concevez l'API de votre bibliothèque de la même manière qu'auparavant. Ne soyez pas complaisant en vous appuyant sur les capacités des méthodes par défaut. Ils constituent un dernier recours. Choisissez les noms avec soin pour éviter les collisions avec d'autres interfaces. Voyons comment se développera le développement pour Java utilisant cette fonctionnalité.
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION