Interfaces en Java

Qu'est-ce qu'une Interface en Java ?

Les interfaces en Java sont des types abstraits qui définissent les méthodes et les variables qu'une classe qui implémente l'interface doit posséder. Leur fonctionnement est similaire à l'héritage de classe, où la classe qui implémente l'interface "hérite" de ses méthodes. Toutefois, une classe peut implémenter plusieurs interfaces simultanément.

Lorsqu'une variable est définie comme étant de type interface, cela signifie qu'elle peut stocker n'importe quelle instance d'une classe qui implémente cette interface. Il est crucial de noter que l'interface elle-même ne peut pas être instanciée directement. Les interfaces sont considérées comme des types de données de référence.

Éléments autorisés dans une Interface

Dans la définition d'une interface, plusieurs éléments peuvent être présents :

  • Variables constantes : Par défaut, elles sont publiques, statiques et finales.
  • Méthodes abstraites : Ces méthodes doivent être redéfinies par la classe qui implémente l'interface.
  • Méthodes statiques : Celles-ci ne sont pas redéfinies, mais accessibles comme toute méthode statique de classe.
  • Méthodes par défaut : Ces méthodes peuvent être redéfinies, mais si elles ne le sont pas, la définition dans l'interface est utilisée.

Il est important de noter qu'aucune méthode d'interface ne peut être protégée ou finale.

Syntaxe d'une Interface

La syntaxe de base pour la définition d'une interface est la suivante :

interface NomDeLInterface {
  String variableConstante = "valeur";

  int methodeAbstraite();

  static void methodeStatique() {
    // Corps de la méthode
  }

  default void methodeParDefaut() {
    // Corps de la méthode
  }
}

Une interface peut comporter un nombre quelconque de ces éléments, mais elle doit en avoir au moins un, elle ne peut pas être vide.

Exemple d'Utilisation des Interfaces

Voyons un exemple concret d'interface en utilisation, avec une interface Aliment :

// Food.java
public interface Food {
  String name();
  default String kind() { return "Food"; }
}

Ensuite, nous définissons une classe Chou qui implémente l'interface Food :

// Cabbage.java
public class Cabbage implements Food {
  @Override
  public String name() { return "Chou"; }
  @Override
  public String kind() { return "Légume"; }
}

Nous définissons également une classe Saucisse :

// Sausage.java
public class Sausage implements Food {
  @Override
  public String name() { return "Saucisse"; }
  @Override
  public String kind() { return "Viande"; }
}

De nombreuses classes peuvent implémenter la même interface, comme avec la classe Pizza :

// Pizza.java
public class Pizza implements Food {
  @Override
  public String name() { return "Pizza"; }
}

Pour démontrer l'interface ainsi que toutes les classes qui l'implémentent, voici un exemple de programme principal :

// Main.java
import java.util.ArrayList;
import java.util.Collection;

public class Main {
  public static void main(String[] args) {
    Collection foods = new ArrayList();
    foods.add(new Cabbage());
    foods.add(new Sausage());
    foods.add(new Pizza());

    for (Food food : foods) {
      System.out.println(food.name() + ": " + food.kind());
    }
  }
}

En exécutant ce code, nous obtiendrons la sortie suivante :

Chou : Légume
Saucisse : Viande
Pizza : Food