Les classes abstraites et les interfaces sont des outils fondamentaux pour réaliser l’abstraction en Java. L’abstraction, dans le contexte de la programmation orientée objet, consiste à masquer les détails d’implémentation aux utilisateurs finaux.
Grâce à l’abstraction, vous êtes conscient des fonctionnalités disponibles, sans pour autant connaître leur fonctionnement interne.
Examinons de plus près ces deux concepts afin de mieux comprendre leur utilité et leur raison d’être.
Classe Abstraite
En Java, une classe abstraite est une classe qui ne peut pas être instanciée directement en tant qu’objet. Elle peut, ou non, contenir des méthodes abstraites. Une méthode abstraite est une méthode déclarée sans corps d’implémentation.
Par exemple, prenons l’exemple d’une classe abstraite nommée GraphicObject, tel que présenté par Oracle.
Pour déclarer une classe comme abstraite, vous devez utiliser le mot-clé `abstract` avant le mot-clé `class`.
abstract class ClasseAbstraite { void executer() { System.out.println("Exécuté"); } }
Une classe abstraite peut être étendue par d’autres classes, agissant ainsi comme une super-classe pour d’autres classes dérivées.
abstract class ClasseAbstraite { void executer() { System.out.println("Exécuté"); } } class ClasseDerivee extends ClasseAbstraite { void nouvelleMethode() { System.out.println("Nouveau"); } @Override void executer() { System.out.println("Remplacé"); } }
Les classes abstraites se révèlent très utiles pour mettre en œuvre des méthodes communes à plusieurs classes héritant d’une même classe abstraite. De plus, la possibilité de définir des méthodes abstraites au sein de ces classes offre une grande flexibilité pour les classes ayant des méthodes similaires, mais des implémentations distinctes. Illustrons cela par un exemple.
Imaginez une voiture possédant des fonctionnalités telles que le démarrage, l’arrêt, la marche arrière, etc. Ces fonctionnalités sont partagées par tous les types de voitures.
Mais qu’en est-il des fonctionnalités d’automatisation, comme la conduite autonome ? L’implémentation de ces fonctionnalités peut varier selon le type de voiture. Voyons comment modéliser cela en programmation orientée objet.
Commençons par créer une classe de base « Voiture » qui sera étendue par différents types de voitures.
abstract class Voiture { void demarrer() { // implémentation System.out.println("La voiture démarre"); } void arreter() { // implémentation System.out.println("Le moteur s'arrête"); } void reculer() { // implémentation System.out.println("Marche arrière activée"); } abstract void conduiteAutonome(); }
Les méthodes `demarrer()`, `arreter()` et `reculer()` sont des méthodes communes à toutes les voitures. Leur implémentation est définie directement dans la classe `Voiture`. Cependant, l’implémentation de la conduite autonome peut varier d’un type de voiture à l’autre. On peut donc déclarer `conduiteAutonome()` comme une méthode abstraite et l’implémenter de manière spécifique dans chaque sous-classe.
class VoitureTypeA extends Voiture { @Override void demarrer() { super.demarrer(); } @Override void arreter() { super.arreter(); } @Override void reculer() { super.reculer(); } void conduiteAutonome() { // implémentation spécifique System.out.println("Mode conduite autonome activé (Type A)"); } }
class VoitureTypeB extends Voiture { // ...méthodes similaires void conduiteAutonome() { // implémentation spécifique // différente de la VoitureTypeA System.out.println("Mode conduite autonome activé (Type B)"); } }
Il est important de noter que si une sous-classe n’implémente pas toutes les méthodes abstraites déclarées dans la classe abstraite, elle doit elle-même être déclarée comme une classe abstraite.
Interface
Une interface est un mécanisme permettant de spécifier les méthodes qu’une classe doit impérativement implémenter. Reprenons l’exemple de la voiture : elle possède des fonctionnalités essentielles comme démarrer, se déplacer et s’arrêter. Ces fonctions sont communes à toutes les voitures.
Ainsi, si vous implémentez une interface « Voiture » dans une classe, vous devez implémenter toutes les méthodes de cette interface pour garantir le bon fonctionnement de la voiture.
Comme pour les classes abstraites, nous ne pouvons pas instancier une interface. Elle peut être perçue comme une classe entièrement abstraite, car elle ne contient que des méthodes abstraites, c’est-à-dire sans corps d’implémentation.
Vous pouvez créer une interface en utilisant le mot-clé `interface`.
interface VoitureInterface { void demarrer(); void arreter(); void deplacer(); }
Implémentez une interface en utilisant le mot-clé `implements` lors de la définition d’une classe.
class VoitureTypeB implements VoitureInterface { public void demarrer() { System.out.println("Démarrée"); } public void arreter() { System.out.println("Arrêtée"); } public void deplacer() { System.out.println("En marche"); } }
Similitudes
La non-instanciation est la principale caractéristique commune entre les classes abstraites et les interfaces.
Différences
Classe Abstraite | Interface | |
Héritage et implémentation | Une seule classe abstraite peut être héritée par une classe. | Plusieurs interfaces peuvent être implémentées par une classe. |
Types de variables | Peut contenir des variables finales, non finales, statiques et non statiques. | Ne peut contenir que des variables statiques et finales. |
Types de méthode | Peut contenir à la fois des méthodes abstraites et non abstraites. | Ne peut contenir que des méthodes abstraites, mais les méthodes statiques sont une exception. |
Modificateurs d’accès | Une classe abstraite peut avoir un modificateur d’accès. | Les signatures de méthode définies dans l’interface sont publiques par défaut. Une interface n’a pas de modificateur d’accès. |
Constructeurs et destructeurs | Peut déclarer des constructeurs et des destructeurs. | Ne peut pas déclarer de constructeurs ou de destructeurs. |
Vitesse | Rapide | Lent |
Quand utiliser la classe abstraite et l’interface ?
Utilisez une classe abstraite lorsque :
- Vous souhaitez partager des méthodes et des champs communs entre plusieurs classes.
- Vous devez déclarer des champs non statiques et non finaux afin de pouvoir modifier l’état des objets auxquels ils sont associés.
Utilisez une interface lorsque :
- Vous voulez définir le comportement d’une classe qui implémente l’interface, sans vous soucier de la manière dont ce comportement est réalisé.
- Vous devez vous assurer qu’une classe implémente toutes les méthodes nécessaires à son fonctionnement correct.
Derniers mots
Les interfaces sont couramment utilisées pour créer des API, car elles définissent une structure permettant de mettre en œuvre des fonctionnalités sans imposer une implémentation spécifique.
Les classes abstraites sont généralement privilégiées pour partager des méthodes, abstraites et non abstraites, entre différentes classes, qui héritent de la classe abstraite pour faciliter la réutilisation du code.
Pour approfondir vos connaissances sur Java, vous pouvez consulter ces formations en ligne. Si vous préparez un entretien sur Java, voici quelques questions pertinentes sur la programmation orientée objet.