Constructeurs par défaut en Java
Je sais que je pose une question sérieuse 101 ici...
J'ai un peu de classe Foo
et une classe Bar
qui s'étend Foo
. Dans Foo
j'ai un constructeur qui prend un ensemble de paramètres qu'il fixe à ses champs. Dériver des classes telles que Bar
n'aura généralement pas besoin de modifier cela. Maintenant, mon IDE me donne "Il n'y a pas de constructeur par défaut disponible dans Foo". D'un peu de Googling cela semble être parce que "les constructeurs ne sont pas hérités". Donc tout beau et bien, mais comment puis-je maintenant que cela fonctionne sans dupliquer ce constructeur dans chaque classe dérivante? Je suppose qu'il y a une approche plus saine?
6 réponses
Utilisez le constructeur super
:
public Bar(int a, double b, ...) {
super(a, b, ...);
}
Donc tout va bien, mais comment puis-je maintenant faire fonctionner cela sans dupliquer ce constructeur dans chaque classe dérivante?
Vous devez dupliquer le constructeur signatures - Si vous voulez que la sous-classe ait des constructeurs avec les mêmes signatures. Mais vous n'avez pas besoin de dupliquer le code - vous enchaînez simplement au constructeur de superclasse:
public Bar(int x, int y) {
super(x, y);
// Any subclass-specific code
}
Bien sûr, si vous pouvez travailler sur les paramètres de superclasse à partir d'un différent ensemble de les paramètres, c'est bien. Par exemple:
public Bar(int x) {
super(x, x * 2);
// Any subclass-specific code
}
Vous avez vraiment besoin de déterminer quelles informations sont nécessaires pour construire un Bar
- Cela devrait dicter vos constructeurs.
Si c'est un problème, il est possible que vous utilisiez trop l'héritage. Il est difficile de dire avec certitude sans aucune idée de ce que sont vos classes réelles, mais vous devriez regarder en utilisant la composition au lieu de l'héritage. Ce n'est pas une panacée, mais cela peut éviter ce genre de chose.
Non, il n'y a plus d'approche "saine". Si votre classe de base n'a pas de constructeur par défaut, vous devez appeler explicitement le constructeur correct de toutes les classes enfants.
Notez que cela ne signifie pas que les classes enfants doivent avoir le exact même constructeur que la classe de base. Par exemple, ceci est parfaitement valide:
class Foo {
protected int a;
protected int b;
protected Foo(final int a, final int b) {
this.a = a;
this.b = b;
}
}
class Bar extends Foo {
protected Bar() {
super(0,0);
}
}
Le problème est résolu avec ceci:
class Foo{
Foo(int a, int b){}
}
class Bar extends Foo{
//Here must be a constructor OR declare a constructor in Foo without parameters
Bar(){super(1,1)} //this is an example
}
L'autre solution est:
class Foo{
Foo(int a, int b){}
Foo(){}
}
class Bar extends Foo{
}
Rappelez-vous que si vous avez un constructeur avec des paramètres dans la superclasse (dans ce cas Foo), le constructeur implicite de la classe enfant (dans ce cas, la barre), aura toujours un appel implicite à " Super () " (doit toujours être un sauf si explicite).
JVM ne fournira pas de constructeur par défaut si vous en avez fourni un pour des raisons de conception. Ce que vous pouvez faire définir constructeur dans la barre avec la même signature et appeler super ().
public Bar(int x,int y) {
super(x,y);
}
Si les paramètres ne sont pas requis et / ou ont des valeurs par défaut, vous pouvez définir le constructeur par défaut (sans paramètres):
class Foo
{
public final int DEFAULT_A = 42;
protected int a;
protected int b;
public Foo(final int a, final int b)
{
this.a = a;
this.b = b;
}
// Is equal to new Foo(Foo.DEFAULT_A, 0);
public Foo()
{
this.a = this.DEFAULT_A;
}
}
class Bar extends Foo {}
class PiBar extends Bar
{
public final int DEFAULT_A = Math.PI;
}