Chaque nouvelle version de Java diffère des précédentes. Comme exemple d'un tel changement par rapport au matériel que nous avons couvert, le langage n'avait pas enumsavant Java 5.
Méthodes par défaut dans les interfaces - 1
Ainsi, Java 8 est sensiblement différent de Java 7. Nous n'ignorerons pas les innovations importantes, bien sûr. Puisque nous parlons d'interfaces dans cette leçon, considérons une mise à jour du langage : les méthodes par défaut dans les interfaces . Vous savez déjà qu'une interface n'implémente pas de comportement . Son but est de décrire quel comportement doit exister dans tous les objets qui implémentent l'interface . Mais les développeurs rencontraient fréquemment des situations où l'implémentation d'une méthode était la même dans toutes les classes. Regardons notre exemple de vieille voiture :

public interface Car {

   public void gas();
  
   public void brake();
}
public class Sedan implements Car {

   @Override
   public void gas() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class Truck implements Car {

   @Override
   public void go() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class F1Car implements Car {
   @Override
   public void go() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}
Selon vous, quel est le principal problème avec ce code ? Vous avez probablement remarqué que nous avons écrit un tas de code en double ! C'est un problème courant en programmation et il faut l'éviter. C'est un autre problème qu'il n'y avait pas de solutions particulières avant la sortie de Java 8. Lorsque cette version est sortie, il est devenu possible de définir des méthodes par défaut et de les implémenter directement dans une interface ! Voici comment procéder :

public interface Car {

   public default void gas() {
       System.out.println("Gas!");
   }

   public default void brake() {
       System.out.println("Brake!");
   }
}

public class Sedan implements Car {

}

public class Truck implements Car {

}

public class F1Car implements Car {

}
Désormais, les méthodes gas()et brake(), qui étaient les mêmes pour toutes les voitures, ont été déplacées dans l'interface, éliminant ainsi le besoin de code en double. Et les méthodes sont disponibles dans chacune des classes !

public class Main {

   public static void main(String[] args) {

       F1Car f1Car = new F1Car();
       Sedan sedan = new Sedan();
       Truck truck = new Truck();
       truck.gas();
       sedan.gas();
       f1Car.brake();
   }
}
Que se passe-t-il s'il y a 100 classes avec une gas()méthode, mais que seulement 99 d'entre elles doivent avoir le même comportement ? Est-ce que ça gâche tout ? Une méthode par défaut ne fonctionnera-t-elle pas dans ce cas ? Bien sûr que non :) Les méthodes d'interface par défaut peuvent être remplacées.

public class UnusualCar implements Car {
   @Override
   public void go() {
       System.out.println("This car accelerates differently!");
   }

   @Override
   public void brake() {
       System.out.println("This car slows down differently!");
   }
}
Tous les 99 autres types de voitures utiliseront la méthode par défaut, tandis que leUnusualCarclasse est une exception. Sans gâcher la vue d'ensemble, il définira sereinement son propre comportement. Héritage multiple dans les interfaces. Comme vous le savez déjà, il n'y a pas d'héritage multiple en Java. Il y a plusieurs raisons à cela. Nous les examinerons en détail dans une leçon séparée. Dans d'autres langages, comme C++, la situation est inversée. Aucun héritage multiple ne présente un défi sérieux, car le même objet peut avoir plusieurs caractéristiques et comportements différents. Par exemple, nous sommes des enfants pour nos parents, des étudiants pour nos professeurs et des patients pour nos médecins. Dans la vraie vie, nous remplissons différents rôles et, par conséquent, nous nous comportons différemment : évidemment, nous interagissons différemment avec les enseignants qu'avec des amis proches. Essayons de traduire cette situation en code. Imaginons que nous ayons deux classes : Étang et Volière. Un étang a besoin d'oiseaux nageurs, tandis qu'une volière a besoin d'oiseaux volants. Pour représenter cela, nous avons créé deux classes de base :FlyingBirdet Waterfowl.

public class Waterfowl {
}

public class FlyingBird {
}
En conséquence, nous enverrons les oiseaux qui héritent FlyingBirdà la volière, tandis que ceux qui en dérivent Waterfowliront à l'étang. Tout semble simple. Mais que devons-nous faire si nous devons définir un canard quelque part ? Les canards nagent et volent. Mais nous n'avons pas d'héritage multiple. Heureusement, Java prend en charge plusieurs implémentations d'interfaces. Si une classe ne peut pas hériter de plusieurs parents, implémenter plusieurs interfaces est facile ! Notre canard peut être aussi bien un oiseau volant qu'un oiseau nageur :) Pour arriver au résultat souhaité, il suffit de faire des FlyingBirdinterfaces Waterfowlplutôt que des classes.

public class Duck implements FlyingBird, Waterfowl {

   // Methods of both interfaces combine easily into one class
  
   @Override
   public void fly() {
       System.out.println("Flying!");
   }

   @Override
   public void swim() {

       System.out.println("Swimming!");
   }
}
Cela signifie que notre programme conserve la capacité de gérer les cours de manière flexible. Lorsque nous combinons cela avec des méthodes par défaut, notre capacité à déterminer le comportement des objets devient presque illimitée ! :)