1. Présentation des interfaces

Aujourd'hui est votre journée pour la connaissance. Un autre sujet nouveau et intéressant est celui des interfaces.

Le concept d' interface est l'enfant des principes d'abstraction et de polymorphisme. Une interface est très similaire à une classe abstraite, dans laquelle toutes les méthodes sont abstraites. Elle se déclare de la même manière qu'une classe, mais on utilise le interfacemot clé.

interface Feline
{
   void purr();
   void meow();
   void growl();
}

Voici quelques faits utiles sur les interfaces :

1. Déclarer une interface

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. Au lieu du classmot-clé, nous écrivons interface.
  2. Il ne contient que des méthodes abstraites (n'écrivez pas le abstractmot-clé)
  3. En fait, les interfaces ont toutespublic les méthodes
2. Héritage d'interface

Une interface ne peut hériter que d'interfaces. Mais une interface peut avoir plusieurs parents. Une autre façon de dire cela est de dire que Java a plusieurs héritages d'interfaces. Exemples:

interface Piece extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. Héritage des classes des interfaces

Une classe peut hériter de plusieurs interfaces (d'une seule classe). Cela se fait à l'aide du implementsmot-clé. Exemple:

abstract class ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

La classe ChessItem est déclarée abstraite : elle implémente toutes les méthodes héritées sauf draw. En d'autres termes, la ChessItemclasse contient une méthode abstraite — draw().

La signification technique des mots-clés extendset implementsest la même : les deux sont un héritage. La distinction a été faite pour améliorer la lisibilité du code. On dit aussi que les classes sont héritées (via extends) et que les interfaces sont implémentées (via implements)

4. variables

Voici la chose la plus importante : les variables ordinaires ne peuvent pas être déclarées dans les interfaces (bien que les variables statiques le puissent).

Mais pourquoi avons-nous besoin d'interfaces ? Quand sont-ils utilisés ? Les interfaces ont deux avantages importants par rapport aux classes :



2. Séparer la « description des méthodes » de leur mise en œuvre.

Auparavant, nous avons dit que si vous souhaitez autoriser les méthodes de votre classe à être appelées à partir d'autres classes, vos méthodes doivent être marquées avec le publicmot-clé. Si vous souhaitez que certaines de ces méthodes soient appelées uniquement depuis votre classe, vous devez les marquer avec le privatemot-clé . En d'autres termes, nous divisons les méthodes de la classe en deux catégories : "pour tout le monde à utiliser" et "uniquement pour notre propre usage".

Les interfaces contribuent à renforcer davantage cette division. Nous créerons une "classe spéciale pour tout le monde" ainsi qu'une deuxième classe "uniquement pour notre propre usage", qui héritera de la première classe. Voici à peu près à quoi cela ressemblerait:

Avant Après
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

Nous avons divisé notre classe en deux : une interface et une classe qui hérite de l' interface . Et quel est l'avantage ici?

De nombreuses classes différentes peuvent implémenter (hériter) la même interface. Et chacun peut avoir son propre comportement. Par exemple, ArrayList LinkedListdeux implémentations différentes de l' Listinterface.

Ainsi, nous cachons non seulement les différentes implémentations, mais également la classe d'implémentation elle-même (puisque nous n'avons besoin que de l'interface dans le code). Cela nous permet d'être très flexibles : pendant que le programme s'exécute, nous pouvons remplacer un objet par un autre, en modifiant le comportement d'un objet sans affecter toutes les classes qui l'utilisent.

C'est une technique très puissante lorsqu'elle est combinée avec le polymorphisme. Pour l'instant, il est loin d'être évident pourquoi vous devriez faire cela. Vous devez d'abord rencontrer des programmes avec des dizaines ou des centaines de classes afin de comprendre que les interfaces peuvent vous rendre la vie tellement plus facile que sans elles.


3. Héritage multiple

En Java, toutes les classes ne peuvent avoir qu'une seule classe parent. Dans d'autres langages de programmation, les classes peuvent souvent avoir plusieurs classes parentes. Ceci est très pratique, mais pose également de nombreux problèmes.

Les créateurs de Java sont arrivés à un compromis : ils interdisaient l'héritage multiple de classes, mais autorisaient l'héritage multiple d'interfaces. Une interface peut avoir plusieurs interfaces parentes. Une classe peut avoir plusieurs interfaces parentes mais une seule classe parente.

Pourquoi ont-ils interdit l'héritage multiple de classes mais autorisé l'héritage multiple d'interfaces ? En raison du soi-disant problème d'héritage du diamant :

Héritage multiple

Lorsque la classe B hérite de la classe A, elle ne sait rien des classes C et D. Il utilise donc les variables de la classe A comme bon lui semble. La classe C fait la même chose : elle utilise les variables de la classe A, mais d'une manière différente. Et tout cela se traduit par un conflit dans la classe D.

Regardons l'exemple simple suivant. Disons que nous avons 3 classes :

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value; }
}

La classe Data stocke la valuevariable. Sa classe descendante XCoordinate utilise cette variable pour stocker la xvaleur, et la YCoordinateclasse descendante l'utilise pour stocker la yvaleur.

Et il fonctionne. Séparément. Mais si nous voulons que la classe XYCoordinates hérite à la fois des classes XCoordinateet YCoordinate, nous obtenons du code défectueux. Cette classe aura les méthodes de ses classes ancêtres, mais elles ne fonctionneront pas correctement, car elles ont le même value variable.

Mais parce que les interfaces ne peuvent pas avoir de variables, elles ne peuvent pas avoir ce genre de conflit. En conséquence, l'héritage multiple d'interfaces est autorisé.