Quand on dispose d’une classe c, on a la possibilité de l’agrandir (ou de l’étendre) en créant une deuxième classe c′. On dit dans ce cas que c′ hérite de c, ou encore que c est la classe mère et c′ la classe fille. Par exemple, considérons les deux classes suivantes :
package heritage; public class ClasseMere { private final int x; public ClasseMere(int x) { this.x = x; } public int getX() { return x; } }
package heritage; public class ClasseFille extends ClasseMere { private final int y; public ClasseFille(int x, int y) { super(x); this.y = y; } public int getY() { return y; } }
Le mot-clé
extends
signifie hérite de. Le mot-clé
super
est le constructeur de la classe mère. Tout ce qui peut
être fait avec la classe mère peut aussi être fait avec la classe
fille. Notez donc que la classe fille est une extension de la
classe mère. On peut par exemple utiliser la classe fille de la façon
suivante :
package heritage; public class TestClasseFille { public static void main(String[] args) { ClasseFille o = new ClasseFille(1, 2); System.out.println("(" + o.getX() + ", " + o.getY() + ")"); } }
Notes bien que comme la classe mère possède une méthode
getX
,
la classe fille la possède aussi. Et l’attribut
x
de tout
instance de la classe mère est aussi un attribut de toute instance de
la classe fille.
En java, une classe ne peut avoir qu’une seule classe mère. Dans
d’autres langages (comme le
C++
) cela est permis, mais pour
des raisons de fiabilité, Java l’interdit.
Object
En java, toutes les classes héritent implicitement d’une classe
Object
.
Considérons l’exemple suivant :
package heritage; public class TestClasseFillePolymorphisme { public static void main(String[] args) { ClasseMere o = new ClasseFille(1, 2); System.out.println(o.getX()); System.out.println(((ClasseFille) o).getY()); } }
On remarque d’une part que o référence un objet de la classe fille de son type. Cela s’appelle le polymorphisme. D’autre part, si l’on souhaite effectuer des opérations spécifiques aux objets de la classe fille, il est nécessaire d’effectuer un cast.
La méthode
toString()
appartient initialement à la classe
Object
. Elle est donc héritée par toutes les classes. Vous
avez la possibilité de la redéfinir, c’est à dire de remplacer la
méthode par défaut par une méthode davantage adaptée à la classe en
question.
L’héritage multiple est interdit en Java. Les interfaces sont un moyen de résoudre en partie le problème.
Une interface est un ensemble de constantes et de méthodes vides.
Il est impossible d’instancier une interface. On utilise une interface
en créant une classe qui en hérite et qui contient le corps des méthodes
qui y sont déclarées..
Dans le cas où la classe mère est une interface, le mot-clé
implements
prend la place de
extends
.
En voici un exemple d’utilisation :
package heritage; import java.util.ArrayList; interface Saluer { public void direBonjour(); } class Bonjour implements Saluer { @Override public void direBonjour() { System.out.println("Bonjour"); } } class Hello implements Saluer { @Override public void direBonjour() { System.out.println("Hello"); } } class GutenTag implements Saluer { @Override public void direBonjour() { System.out.println("Guten tag"); } } public class ExempleInterface { public static void main(String[] args) { Saluer s = new Bonjour(); s.direBonjour(); s = new Hello(); s.direBonjour(); ArrayList<Saluer> arrayList = new ArrayList<Saluer>(); arrayList.add(new Bonjour()); arrayList.add(new Hello()); arrayList.add(new GutenTag()); for (Saluer saluer : arrayList) saluer.direBonjour(); } }
Vous remarquez que la méthode
Saluer
est implémentée
par les trois classes
Bonjour
,
Hello
et
GutenTag
, qui contiennent trois façons différentes
de programmer la méthode
public void saluer()
.
Le polymorphisme permet de mettre dans une référence de type
Saluer
tout objet dont le type hérite de
Saluer
.
On peut voir une interface comme un contrat :
La restriction interdisant l’héritage multiple en Java ne s’applique pas aux interfaces. Une classe peut implémenter plusieurs interfaces.
Nous voulons représenter des sommes dans des devises différentes et implémenter automatiquement les conversions. Nous allons créer une classe devise qui contiendra l’attribut somme et nous utiliserons l’héritage pour implémenter les spécificités des diverses devises (Euros, Dollars, Livres, ...).
package heritage; public abstract class Devise { private double somme = 0; /* * Nombre de devises pour 1$. */ public abstract double getCours(); public abstract String getUnite(); protected void setSomme(double somme) { this.somme = somme; } protected void setSomme(Devise d) { setSomme(d.getSomme() * this.getCours() / d.getCours()); } public double getSomme() { return somme; } @Override public String toString() { return "somme = " + somme + " " + getUnite(); } public static void main(String[] args) { Devise devise = new Dollars(12); System.out.println(devise); devise = new Euros(devise); System.out.println(devise); devise = new Livres(devise); System.out.println(devise); devise = new Dollars(devise); System.out.println(devise); } } class Livres extends Devise { public Livres(Devise d) { setSomme(d); } public Livres(double somme) { setSomme(somme); } @Override public double getCours() { return 0.76636574; } @Override public String getUnite() { return "Livres"; } } class Euros extends Devise { public Euros(Devise d) { setSomme(d); } public Euros(double somme) { setSomme(somme); } @Override public double getCours() { return 0.895744319; } @Override public String getUnite() { return "Euros"; } } class Dollars extends Devise { public Dollars(Devise d) { setSomme(d); } public Dollars(double somme) { setSomme(somme); } @Override public double getCours() { return 1.; } @Override public String getUnite() { return "Dollars"; } }
Ces classes permettent de prendre en charge automatiquement les
conversions entre devises. La classe
Devise
contient une
méthode
setSomme
qui est
surchargée et qui peut prendre en paramètre soit une somme exprimée
dans la bonne unité, soit une autre devise.
On remarque qu’il est impossible d’implémenter
getCours()
car
le cours varie selon la devise. La classe
Euros
hérite de la
classe
Devise
et implémente
getCours()
. La classe
Dollars
fonctionne de façon similaire.