web-dev-qa-db-fra.com

Constructeurs par défaut en Java

Je sais que je pose une question sérieuse 101 ici ...

J'ai une classe Foo et une classe Bar qui étend Foo. Dans Foo, j'ai un constructeur qui prend un ensemble de paramètres qu'il définit dans ses champs. Les classes dérivées telles que Bar n'auront 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" . Cela semble provenir d’un peu de Google car "les constructeurs ne sont pas hérités". Donc, tout va bien, mais comment puis-je maintenant faire fonctionner cela sans dupliquer ce constructeur dans chaque classe dérivée? Je suppose qu'il y a une approche plus saine.

50
Jeroen De Dauw

Utilisez le constructeur super:

public Bar(int a, double b, ...) {
    super(a, b, ...);
}
61
arshajii

Donc, tout va bien, mais comment puis-je maintenant faire fonctionner cela sans dupliquer ce constructeur dans chaque classe dérivée?

Vous devez dupliquer le constructeur signatures - si vous souhaitez que la sous-classe ait des constructeurs avec les mêmes signatures. Mais vous n'avez pas besoin de dupliquer le code - vous venez de la chaîner au constructeur de la superclasse:

public Bar(int x, int y) {
    super(x, y);
    // Any subclass-specific code
}

Bien sûr, si vous pouvez définir les paramètres de la super-classe à partir d'un jeu de paramètres différent , c'est très bien. Par exemple:

public Bar(int x) {
    super(x, x * 2);
    // Any subclass-specific code
}

Vous devez vraiment déterminer quelles informations sont nécessaires pour construire une Bar - qui 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 réelles classes, mais vous devriez envisager d'utiliser la composition plutôt que l'héritage. Ce n'est pas une panacée, mais cela peut éviter ce genre de chose.

16
Jon Skeet

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

}

Une 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 SuperClass (dans ce cas, Foo), le constructeur implicite de la classe enfant (dans ce cas, Bar) aura toujours un appel implicite à " Super () "(doit toujours être un sauf si explicite).

3
Gaston Flores

Non, il n'y a plus d'approche "saine". Si votre classe de base n'a pas de constructeur par défaut, vous devez explicitement appeler le constructeur approprié à partir de toutes les classes enfants.

Notez que cela ne signifie pas que les classes enfants doivent avoir le même constructeur exact 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
m0skit0

Cette erreur peut également se produire car vous appelez votre dernier constructeur en dernier. Vous devrez peut-être le déplacer pour qu'il s'agisse de la première déclaration:

    public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
        mFragmentList  = fragmentList;
        super(manager);

    }

    public SectionsPagerAdapter(FragmentManager manager, List<Fragment> fragmentList) {
        super(manager); --> this should come first
        mFragmentList  = fragmentList;
    }
0
live-love

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éfinit le constructeur dans Bar avec la même signature et appelle super ().

public Bar(int x,int y) {
    super(x,y);
}
0
Aniket Thakur

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ètre):

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
Vasilii Suricov