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?

47
demandé sur arshajii 2013-06-12 18:41:12

6 réponses

Utilisez le constructeur super:

public Bar(int a, double b, ...) {
    super(a, b, ...);
}
58
répondu arshajii 2013-06-12 14:43:23

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.

15
répondu Jon Skeet 2013-06-12 14:44:53

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);
    }
}
3
répondu m0skit0 2013-06-12 14:50:08

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).

2
répondu Gaston Flores 2013-06-12 15:00:17

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);
}
0
répondu Aniket Thakur 2013-06-13 09:44:43

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;

}
0
répondu Vasilii Suricov 2018-07-24 17:21:12