pdf - e-book - archive - github.com

1.11  Héritage

1.11.1  Héritage

Le principe

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;
 }
}

Télécharger le fichier

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;
 }
}

Télécharger le fichier

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() + ")");
 }
}

Télécharger le fichier

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.

Héritage simple Vs. héritage multiple

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.

1.11.2  Polymorphisme

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());
 }
}

Télécharger le fichier

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.

1.11.3  Redéfinition de méthodes

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.

1.11.4  Interfaces

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();
 }
}

Télécharger le fichier

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.

1.11.5  Classes Abstraites

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";
 }
}

Télécharger le fichier

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.