De la même façon qu'il est possible d'empêcher quelqu'un d'étendre une classe, ou de surcharger une méthode, il est possible de forcer l'extension ou la surcharge, en utilisant le mot-clé
abstract
.
Formellement une classe abstraite n'est pas différente d'une classe normale. Simplement, elle est déclarée en ajoutant le mot-clé
abstract
, comme dans l'exemple suivant.
Exemple 86. Classe abstraite
public abstract class A {
public abstract void ouSuisJe() ;
}
On peut déclarer autant de méthodes abstraites que l'on veut dans une classe abstraite, y compris ne pas en déclarer du tout. Une méthode abstraite, comme dans notre exemple, ne comporte qu'une déclaration de signature ; elle n'a pas de corps. On peut alors se poser la question : comment fait-on pour exéctuter une telle méthode ? La réponse est simple : on ne peut pas l'exécuter en l'état.
Une classe abstraite ne peut pas être instanciée. Il est nécessaire de créer une classe concrète (c'est-à-dire non abstraite !) qui l'étende, et d'instancier cette classe concrète. Toute classe concrête qui étend une classe abstraite doit fournir un corps de méthode (on parle alors d'implémentation, un beau mot de la langue française...) pour toutes les méthodes abstraites de cette classe abstraite. Dans notre exemple, on peut alors écrire le code de l'exemple suivant.
Exemple 87. Extension d'une classe abstraite - 1
public class B extends A {
public void ouSuisJe() {
System.out.println("J'y suis j'y reste !") ;
}
}
D'une façon générale :
-
une classe abstraite peut étendre une autre classe abstraite ;
-
une classe abstraite peut étendre une classe concrète ;
-
une classe concrète qui étend une ou plusieurs classes abstraites (indirectement), doit obligatoirement fournir une implémentation pour toutes les méthodes abstraites existantes.
Voyons ceci sur un exemple.
Exemple 88. Extension d'une classe abstraite - 2
public abstract class A {
public abstract void ouSuisJe() ;
}
public abstract class B extends A {
public void ouSuisJe() {
System.out.println("Il est passé par ici") ;
}
}
public abstract class C extends B {
public abstract void ouVasTu() ;
}
public class D extends C {
public void ouVasTu() {
System.out.println("J'y retourne") ;
}
}
Dans notre exemple :
-
on ne peut pas instancier
A
, qui est abstraite ;
-
on ne peut pas non plus instancier
B
, car même si elle n'a pas de méthode abstraite, elle est tout de même déclarée abstraite ;
-
on ne peut pas instancier
C
;
-
on peut instancier
D
, qui possède bien une implémentation pour
ouSuisJe()
(par extension de
B
), et pour
ouVasTu()
.
Les classes abstraites sont très utilisées dans l'API standard. La partie graphique (Swing) en possède de nombreuses. On peut énoncer deux principes pour justifier la création d'une classe abstraite :
-
la classe que l'on écrit va être étendue par plusieurs classes ;
-
ces différentes classes vont être utilisées par des méthodes communes, et seront déclarées par le nom de la super classe abstraite.
Si ces deux conditions ne sont pas réunies, alors écrire une classe abstraite ne présente aucun intérêt.