Pourquoi les constructeurs existent
Sur la page précédente, vous avez créé des classes et des objets avec new. Un constructeur est le code qui s'exécute réellement pendant cet appel à new. Son unique but est de vous rendre un objet prêt à l'emploi : tous ses champs obligatoires renseignés, aucun état à moitié initialisé.
Un constructeur ressemble à une méthode, avec deux différences : il porte le même nom que la classe et il n'a aucun type de retour, pas même void.
new Point(3, 4) alloue l'objet puis exécute le corps du constructeur avec x = 3 et y = 4. Au moment où new se termine, p est entièrement initialisé.
Le mot-clé this
Dans le constructeur ci-dessus, les paramètres s'appellent x et y, comme les champs. this.x désigne « le champ x appartenant à cet objet », tandis que x seul fait référence au paramètre. Sans this, x = x affecterait simplement le paramètre à lui-même et laisserait le champ inchangé.
Vous n'avez besoin de this que lorsqu'un paramètre masque un champ, mais beaucoup l'utilisent partout par souci de clarté. L'erreur courante est de l'oublier quand les noms entrent en collision : le code compile, s'exécute et laisse silencieusement vos champs à leurs valeurs par défaut (null, 0, false).
Le constructeur par défaut
Si vous n'écrivez jamais de constructeur, Java fournit discrètement un constructeur par défaut : un constructeur public, sans argument, qui ne fait rien de plus. C'est pourquoi new fonctionnait sur des classes qui n'avaient aucun constructeur.
Le piège : dès que vous écrivez un constructeur, le gratuit disparaît.
class Box {
int size;
Box(int size) { // il n'y a plus de constructeur sans argument
this.size = size;
}
}
new Box(); // erreur de compilation : aucun constructeur Box() n'existe
Si vous voulez quand même que new Box() fonctionne, déclarez vous-même le constructeur sans argument :
La surcharge de constructeurs
Une classe peut avoir plusieurs constructeurs tant que leurs listes de paramètres diffèrent : ce n'est que la surcharge de méthodes appliquée aux constructeurs. Chacun propose une façon différente de construire l'objet.
Java choisit le constructeur correspondant en fonction du nombre et des types d'arguments que vous passez à new.
Le chaînage avec this()
Remarquez la duplication ci-dessus : chaque constructeur affecte lui-même les champs. Vous pouvez l'éviter en faisant qu'un constructeur en appelle un autre avec this(...). L'appel doit être la première instruction du constructeur.
Maintenant, l'initialisation réelle tient en un seul endroit. Les constructeurs plus petits se contentent de renseigner les valeurs par défaut et de transmettre le travail. Si vous essayez un jour de placer une instruction avant this(...), le compilateur la rejette.
Les constructeurs et super()
Chaque constructeur appelle implicitement d'abord le constructeur de sa superclasse. Si vous n'écrivez rien, Java insère un super() caché (le constructeur sans argument de la superclasse) en haut du corps. Vous travaillerez directement avec cela dès que vous commencerez à créer des sous-classes, ce qui est le prochain sujet.
class Animal {
String name;
Animal(String name) { this.name = name; }
}
class Dog extends Animal {
Dog(String name) {
super(name); // il faut ici appeler explicitement le constructeur du parent
}
}
Comme Animal n'a pas de constructeur sans argument, Dog doit appeler super(name) explicitement : il n'y a aucun super() gratuit sur lequel se rabattre. Comme this(), un appel à super(...) doit être la première instruction du constructeur.
Suite : L'héritage
Les constructeurs initialisent un seul objet, mais super() laissait déjà entrevoir quelque chose de plus grand : les classes peuvent s'appuyer sur d'autres classes, en réutilisant leurs champs, leurs méthodes et leurs constructeurs. Cette relation, une classe qui en étend une autre, c'est l'héritage, et c'est la prochaine page.
Questions fréquentes
Qu'est-ce qu'un constructeur en Java ?
Un constructeur est une méthode spéciale qui s'exécute lorsque vous créez un objet avec new. Il porte le même nom que la classe et n'a aucun type de retour (pas même void). Son rôle est de placer le nouvel objet dans un état initial valide, généralement en affectant les arguments du constructeur aux champs de l'objet.
Quelle est la différence entre un constructeur et une méthode en Java ?
Un constructeur porte exactement le même nom que la classe, ne déclare aucun type de retour et ne peut être invoqué qu'avec new lors de la création d'un objet. Une méthode ordinaire a son propre nom, déclare un type de retour (ou void) et est appelée sur un objet déjà existant. Les constructeurs initialisent ; les méthodes font le travail ensuite.
Que se passe-t-il si je n'écris aucun constructeur en Java ?
Le compilateur vous offre gratuitement un constructeur par défaut sans argument, qui ne prend aucun paramètre et ne fait rien de plus que l'appel implicite à super(). Mais dès que vous écrivez n'importe quel constructeur vous-même, ce constructeur gratuit disparaît : donc si vous ajoutez un constructeur paramétré tout en voulant que new Thing() continue de fonctionner, vous devez déclarer explicitement le constructeur sans argument.