La surcharge

La surcharge (overloading en anglais) ou surdéfinition est la possibilité de définir plusieurs méthodes de même nom dans la même classe.

La surcharge est également possible pour le constructeur d'une classe, autrement dit une classe peut avoir plusieurs constructeurs de même nom.

Présentation de l'exemple

Pour expliquer la surcharge, nous utiliseront le projet Voiture5 que vous trouverez dans le dossier Exemple-Java-ProgObjet1/Voiture5. Dans ce nouveau projet une voiture est à présent définie par quatre attributs:

Voici la fenêtre du projet:

Voiture5.jpg, 29kB

L'utilisateur peut crééer une voiture en donnant plus ou moins d'informations. La seule donnée obligatoire est le numéro d'immatriculation. Pour réaliser ceci nous allons surcharger le constructeur de la classe, c'est à dire définir plusieurs constructeurs permettant de crééer une instance de la classe Voiture à partir de données différentes.

Pour faire rouler la voiture, il y a deux boutons qui utilisent deux versions différentes de la méthode Rouler. Cette méthode sera donc surchargée.

Surcharge du constructeur

Le constructeur d'une classe sert souvent à intialiser les attributs de la nouvelle instance créée à partir de différentes valeurs passées en paramètres. Pour l'utilisateur de la classe, il peut être pratique de disposer de plusieurs constructeurs afin qu'il puisse choisir les valeurs d'initialisation du nouvel objet.

Par exemple pour pouvoir créer une voiture à partir de son numéro d'immatriculation, nous définissons le constructeur suivant:

 Voiture (String im)
  {
     Immat = im;
  }

Les valeurs des autres attributs seront alors les valeurs par défauts définies dans la déclaration de la classe:

 int  Compteur = 0;
 double Niveau = 0;
 int Conso = 6;
  ....

Autrement dit, avec le constructeur précédent, on récupère une voiture avec un compteur kilométrique à zéro, pas d'essence dans le réservoir et une consommation d'essence de 6 litres pour 100 km.

On pourrait définir un autre constructeur de la manière suivante:

 Voiture (String im, int c)
  {
     Immat = im;
     Compteur = c; 
  }

Ce nouveau constructeur permettrait de créer une voiture en précisant son numéro d'immatriculation ainsi qu'une valeur initiale du compteur kilométrique.

Utilisation de this

Si vous ouvrez le fichier Voiture.java, vous constaterez que nous n'avons pas définie ce deuxième constructeur comme précedemment, mais comme ceci:

Voiture (String im, int c)
  {
     this(im);
     Compteur = c; 
  }

Vous rencontrez ici une première utilisation du mot clé this (il a également une autre signification que nous verrons ultérieurement). Si ce mot clé est suivi de parenthèses, le compilateur Java interprète ceci comme un appel du constucteur. Autrement dit, l'instruction this (im) est un appel du premier constructeur à l'intérieur du second.

Dans cet exemple, l'utilisation de this a assez peu d'intérêt puisque nous n'avons rien gagné en lignes de code. Mais voici, un troisième exemple de constructeur où elle devient plus intéressante:

 Voiture (String im, int c, double ne)
  {
      this (im,c);
      Niveau = ne;
  }

La première instruction appelle le deuxième constructeur, ce qui nous fait gagner une ligne de code. Sans utiliser this, on aurait écrit:

 Voiture (String im, int c, double ne)
  {
      Immat = im;
      Compteur = c;
      Niveau = ne;
  }

Attention: pour que this fonctionne correctement en tant qu'appel de constructeur à l'intérieur d'un autre, ce doit être la première instruction du constructeur.

Déclarations conflictuelles

Rappelons qu'une voiture est définie par quatre attributs:

Parmis ces quatre attributs, seul le numéro d'immatriculation doit être obligatoirement renseigné par l'utilisateur. Les autres attributs étant facultatifs, cela nous donne théoriquement huit constructeurs possibles selon les attributs définis.

Le tableau suivant résume les huits manières de définir le constructeur. La présence d'une croix signifie que le paramètre figure parmis les paramètres formels du constructeur.

Si vous lisez attentivement le code de la classe Voiture (fichier Voiture.java), vous constaterez que nous n'avons déclarer que sept constructeurs. Un des constructeurs a été mis en commentaire car il déclenche une erreur de compilation. Voici son code:

 Voiture (String im, int cons)
  {
      this(im);
      Conso = cons;
  }

Pourquoi cela engendre-t-il une erreur de compilation ?

Le problème vient du fait que ce constructeur entre en conflit avec le constructeur 2:

Voiture (String im, int c)
  {
     this(im);
     Compteur = c; 
  }

On constate que ces deux constructeurs ont des paramètres de même type: le premier est de type String et le deuxième de type int. Or c'est le type des paramètres effectifs qui va permettre de déterminer le constructeur à utiliser lors de l'appel.

Supposons que l'on utilise l'instruction suivante pour créer une nouvelle voiture:

Voiture v = new Voiture ("4017 ZX 67",7);

Comment le compilateur pourrait-il savoir s'il s'agit de créer une voiture avec 7 km au compteur ou une voiture avec une consommation de 7 litres pour 100 km?

Afin d'éviter ce genre de situation ambigue, le compilation refuse de surcharger une méthode s'il existe déjà une déclaration de cette méthode avec des paramètres formels de même type (plus précisément si la liste des types des paramètres dans l'ordre où ils sont écrits est la même).

Surcharge d'une méthode

A quelques détails près, la surcharge d'une méthode suit le même principe que celle d'un constructeur. Il est possible de surcharger une méthode à condition qu'il n'existe pas déjà une méthode de même nom avec des paramètres de même type (dans l'ordre où ils sont déclarés).

Dans le projet Voiture5, nous avons surchargé la méthode Rouler. La première version de cette méthode est appelée lorsque l'utilisateur clique sur le bouton Rouler. Voici son code:

boolean Rouler (int Km)
  {
    if (Consommation_Theorique(Km) <= Niveau)
     {Compteur = Compteur + Km ; 
      Niveau = Niveau - Consommation_Theorique(Km);
      return false;
     }
     else
     {
      Compteur = Compteur + Distance_Theorique(Niveau);
      Niveau = 0;
      return true;
     }
  }

Le paramètre formel Km représente le nombre de kilomètres à parcourir. Le résultat retourné est un booléen qui vaudra true si la voiture tombe en panne d'essence. Cela se produit lorsque le niveau d'essence est insuffisant pour parcourir la distance souhaitée. Dans ce cas, la voiture roule jusqu'à consommer toute l'essence contenue dans le réservoir.

Pour savoir s'il reste assez d'essence dans le réservoir, nous utilisons la méthode Consommation_Theorique qui calcule la consommation théorique d'essence en fonction de la distance parcourue et de la consommation de la voiture.

S'il ne reste pas assez d'essence, la voiture ne va pas parcourir la distance souhaitée, mais seulement la distance théoriquement possible avec le niveau d'essence restant. Cette distance est calculée par la méthode Distance_Theorique qui calcule la distance pouvant être parcourue par la voiture pour une quantité d'essence donnée en tenant compte de sa consommation.

La deuxième version de la méthode Rouler est plus sophistiquée: elle possède un paramètre supplementaire (si_possible) de type booléen. Si la valeur de ce paramètre est true, elle refuse de faire rouler la voiture si la quantité d'essence est théoriquement insuffisante. Sinon, elle se comporte exactement comme la méthode rouler précédente. Cette méthode est appelée lorsque l'on clique sur le bouton Rouler (si possible). Voici son code:

boolean Rouler (int Km,  boolean si_possible)
{
  if (!si_possible)
    return Rouler(Km);
  else
       if (Consommation_Theorique(Km) <= Niveau)
       {Compteur = Compteur + Km ; 
        Niveau = Niveau - Consommation_Theorique(Km);
         return true;
       } 
       else return false;           
}

Lorsque si_possible vaut false, on appelle la méthode Rouler précédente. Sinon, le résultat retourné est true si le niveau d'essence est suffisant (dans ce cas on fait rouler la voiture sur la distance souhaitée) et false sinon (dans ce cas on ne fait pas rouler la voiture).