certification java

OCPJP 6 – Jour 5 – Méthodes Var-args & Constructeurs

Les « var-args » (ou « ellipses ») permettent de créer des méthodes (ou des constructeurs) avec un nombre d’arguments variable. Un constructeur se définit comme une méthode standard, mais ne renvoie aucune valeur. Le rôle du constructeur est de déclarer et de permettre d’initialiser les données membres de la classe, ainsi que de permettre différentes actions (définies par le concepteur de la classe) lors de l’instanciation.

5.1 – Var-args : méthodes à arguments variables

Depuis le JDK 5.0, il est possible de définir une méthode dont le nombre d’arguments est variable.

La notation « … » utilisée dans un tel contexte est appelée « ellipse ». L’ellipse concerne des arguments d’un type quelconque, primitif ou objet et peut être accompagnée d’arguments classiques :

Les méthodes à arguments variables obéissent à certaines règles :

  • Une ellipse est placée après le type de l’objet
  • Une ellipse est unique dans une méthode
  • Une ellipse est toujours le dernier argument de la méthode

Var-args valides


Var-args invalides

5.2 – Constructeurs

Définition

Lorsque qu’un objet est créé (instanciation d’une classe), une méthode générique, appelée constructeur est invoquée. Un constructeur n’est rien d’autre qu’une méthode, sans valeur de retour (même void), portant le même nom que la classe. Il peut disposer d’un nombre quelconque d’arguments (même des var-args) ou éventuellement aucun.

Exemple :

Un constructeur ne peut pas être appelé directement depuis une autre méthode :

De même, un constructeur ne peut être invoqué directement :

Les constructeurs obéissent à certaines règles :

  • un constructeur porte le même nom que la classe dans laquelle il est défini
  • un constructeur n’a pas de type de retour (même pas void)
  • un constructeur peut être associé aux quatre modificateurs d’accès : public, default, protected, private
  • un constructeur ne peut pas être, en toute logique, associé aux modificateurs static, abstract et final
  • un constructeur peut avoir des arguments et même une ellipse
  • un constructeur ne peut être appelé directement.


Constructeurs valides


Constructeurs invalides



Constructeur par défaut

Lorsqu’un objet est créé (instanciation d’une classe), un constructeur est toujours invoqué, même si celui-ci n’est pas déclaré explicitement dans la classe.

Toutes les classes, même les classes abstraites, possèdent un constructeur, même si celui-ci n’est pas déclaré explicitement.

Ainsi, si vous déclarez une classe sans constructeur…

…un constructeur par défaut est ajouté et le compilateur générera le code suivant :

Et vous pourrez, en toute légalité, instancier un objet Plane :

Dès qu’une classe possède au moins un constructeur, le compilateur n’ajoutera pas de constructeur par défaut et ce pseudo-constructeur par défaut ne pourra être utilisé, comme le montre cet exemple :

Exemples où le compilateur n’ajoutera pas de constructeur par défaut :

Exemples où le compilateur ajoutera un constructeur par défaut :

Les constructeurs obéissent à certaines règles :

  • Toutes les classes, mêmes abstraites, possèdent (explicitement ou non) un constructeur
  • Les interfaces ne possèdent pas de constructeur (ce ne sont pas des classes !)
  • un constructeur n’est pas obligatoire dans une classe (un constructeur par défaut sans argument est défini par le compilateur Java si la classe n’en possède pas)
  • un constructeur par défaut est ajouté, si et seulement si, aucun constructeur n’a été déclaré dans la classe


Constructeurs et héritage

Pour tout objet créé, la première instruction du constructeur de cette classe est d’invoquer le constructeur de sa classe mère grâce à l’appel implicite de la méthode super(). Cette classe mère va, à son tour, invoquer le constructeur de sa classe mère et ainsi de suite. Il existe donc un enchaînement d’invocation de constructeurs. Cette cascade d’appels aux constructeurs s’arrête dès que l’on atteint le constructeur de la classe Object.

La classe Object est la mère de toutes les classes ; toute classe est dérivée directement ou indirectement de la classe Object. Ainsi, lors de la création d’un objet, les premières instructions exécutées sont celles du constructeur de la classe Object suivi des instructions des autres constructeurs dans l’ordre de la hiérarchie de dérivation des classes.

Exemple:

Le code précédent générera sur la sortie standard :

  1. Le constructeur de la classe Spitfire est invoqué. Chaque constructeur invoque le constructeur de sa classe mère avec un appel implicite de la méthode super()
  2. Le constructeur de la classe Plane est invoqué (Plane est la classe mère de Spitfire)
  3. Le constructeur de la classe Object est invoqué (Object est la classe mère de Plane même si cette dernière n’en dérive pas explicitement avec l’omission du extends Object)
  4. Le code du constructeur de la classe Object est exécuté
  5. Le code du constructeur de la classe Plane est exécuté
  6. Le code du constructeur de la classe Spitfire est exécuté.

var-args

super(…)

Dans chaque constructeur, le compilateur ajoutera, si celle-ci n’est pas déjà présente, l’instruction super()

CodeCode généré par le compilateur



















Le compilateur n’a rien besoin d’ajouter.




Abordons le cas maintenant où le constructeur de la classe mère possède des arguments :

Comme vu précédemment, le compilateur ajoutera l’instruction super() sans argument dans le constructeur de la sous-classe :

Dans cet exemple, la classe Plane ne possède pas de constructeur sans argument et lorsque que la sous-classe invoquera ce constructeur, la compilation échouera.

Des ajustements sont possibles pour contourner le problème. La première solution est d’ajouter explicitement l’instruction super() avec les arguments correspondant au constructeur de la classe mère :

Une seconde solution est d’ajouter un constructeur sans argument dans la classe mère et c’est ce nouveau constructeur qui sera invoqué dans la classe de base :


this(…)

L’instruction this() permet d’appeler un autre constructeur au sein de la même classe.


super(…) & this(…)

L’instruction super() et l’instruction this() doivent toujours être les premières instructions du constructeur sachant que celles-ci ne peuvent être utilisées toutes les deux dans un même constructeur.

Si une instruction this() est présente dans le constructeur, l’instruction super() ne sera pas ajoutée et le constructeur de la classe parente ne sera pas invoqué.

Ceci dit, dans une même classe, le constructeur de la classe parente doit toujours être invoqué à un moment donné. Cela signifie que, si un constructeur possède une instruction this(), un autre constructeur doit exister, quelque part, dans cette classe et faire appel (explicitement ou non) au constructeur de la classe parente.

Dans le code précédent, le constructeur Spitfire () { ... } possède une instruction this(). Le compilateur n’ajoutera pas l’instruction super() dans ce constructeur mais dans le deuxième constructeur Spitfire (String name) { ... }.

Mais alors que se passerait-il dans le cas où chaque constructeur de la classe posséderait une instruction this() ?

L’instruction super() ne pourra être ajouté dans aucun des constructeurs de la classe Spitfire() et pourtant celle-ci est nécessaire.

Avec un tel code, la stack explose et l’erreur suivante est générée :


Auteur
AuteurEdouard WATTECAMPS

0 réponses

Répondre

Se joindre à la discussion ?
Vous êtes libre de contribuer !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *