94 votes

Erreur Java : Le super constructeur implicite n'est pas défini pour le constructeur par défaut.

J'ai un code Java simple dont la structure ressemble à celle-ci :

abstract public class BaseClass {
    String someString;
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public ASubClass(String someString) {
        super(someString);
    }
    public String getName() {
        return "name value for ASubClass";
    }
}

Je vais avoir un certain nombre de sous-classes de BaseClass chacun mettant en œuvre le getName() à sa manière ( modèle de méthode ).

Cela fonctionne bien, mais je n'aime pas avoir le constructeur redondant dans les sous-classes. C'est plus à taper et c'est difficile à maintenir. Si je modifiais la signature de la méthode BaseClass constructor, je devrais changer toutes les sous-classes.

Lorsque je supprime le constructeur des sous-classes, j'obtiens cette erreur de compilation :

Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor

Ce que j'essaie de faire est-il possible ?

1 votes

S'il vous plaît, laissez le constructeur 'redondant' ! Il préserve la lisibilité de votre code et tous les IDE modernes peuvent le créer automatiquement, il vous suffit donc de saisir un raccourci.

3 votes

En relisant ma propre question un an plus tard, je me suis rendu compte que j'aurais pu supprimer les constructeurs (y compris dans la classe de base) comme l'a suggéré Matt B, et utiliser une méthode de fabrique statique pour construire les instances.

149voto

matt b Points 73770

Vous obtenez cette erreur parce qu'une classe qui n'a pas de constructeur a une valeur de par défaut qui est sans argument et est équivalent au code suivant :

public ACSubClass() {
    super();
}

Cependant, étant donné que votre BaseClass déclare un constructeur (et n'a donc pas le constructeur par défaut, sans argument, que le compilateur fournirait autrement), ceci est illégal - une classe qui étend BaseClass ne peut pas appeler super(); car il n'y a pas de constructeur sans argument dans BaseClass.

Ceci est probablement un peu contre-intuitif car vous pourriez penser qu'une sous-classe possède automatiquement tous les constructeurs de la classe de base.

La façon la plus simple de contourner ce problème est de ne pas déclarer de constructeur dans la classe de base (et donc d'avoir le constructeur par défaut, sans argument) ou d'avoir un constructeur sans argument déclaré (soit par lui-même, soit avec d'autres constructeurs). Mais souvent cette approche ne peut pas être appliquée - parce que vous avez besoin des arguments passés dans le constructeur pour construire une instance légitime de la classe.

17 votes

"C'est probablement un peu contre-intuitif parce que vous pourriez penser qu'une sous-classe a automatiquement tout constructeur que la classe de base a." +1

2 votes

Pour la postérité, je vais suggérer ma solution pour les futurs lecteurs : créer un constructeur sans argument dans le fichier BaseClass mais faites-lui simplement lancer un UnsupportedOperationException ou autre. Ce n'est pas la meilleure solution (elle suggère faussement que la classe peut supporter un constructeur sans argument), mais c'est la meilleure que je puisse imaginer.

51voto

MF.OX Points 141

Pour ceux qui ont cherché cette erreur sur Google et qui sont arrivés ici : il peut y avoir une autre raison pour la recevoir. Eclipse donne cette erreur lorsque vous avez une configuration de projet - mismatch de configuration du système.

Par exemple, si vous importez un projet Java 1.7 dans Eclipse et que vous n'avez pas configuré correctement la version 1.7, vous obtiendrez cette erreur. Vous pouvez alors soit aller dans Project - Preference - Java - Compiler y switch to 1.6 or earlier ; ou allez sur Window - Preferences - Java - Installed JREs et ajoutez/réparez votre installation JRE 1.7.

2 votes

Je viens de recevoir cette erreur sans raison apparente dans Eclipse. J'ai ensuite nettoyé l'espace de travail (menu Project -> Clean...) et elle a disparu.

8voto

OscarRyz Points 82553

C'est possible, mais pas de la manière dont vous l'envisagez.

Vous devez ajouter un constructeur sans arguments à la classe de base et c'est tout !

public abstract class A {
    private String name;
    public A(){
        this.name = getName();
    }
    public abstract String getName();

    public String toString(){
        return "simple class name: " + this.getClass().getSimpleName() + " name:\"" + this.name + "\"";
    }
}
class B extends A {
    public String getName(){
        return "my name is B";
    }
    public static void main( String [] args ) {
        System.out.println( new C() );
    }
}
class C extends A {
    public String getName() {
        return "Zee";
    }
}

Lorsque vous n'ajoutez pas de constructeur ( any ) à une classe, le compilateur ajoute le contructeur no arg par défaut pour vous.

Lorsque le defualt no arg appelle super() ; et puisque vous ne l'avez pas dans la super classe vous obtenez ce message d'erreur.

C'est à peu près la question qu'il se pose.

Maintenant, en élargissant la réponse :

Savez-vous que la création d'une sous-classe (comportement) pour spécifier une valeur différente (données) n'a pas de sens ? J'espère que vous le savez.

Si la seule chose qui change est le "nom", alors une seule classe paramétrée est suffisante !

Donc tu n'as pas besoin de ça :

MyClass a = new A("A");
MyClass b = new B("B");
MyClass c = new C("C");
MyClass d = new D("D");

o

MyClass a = new A(); // internally setting "A" "B", "C" etc.
MyClass b = new B();
MyClass c = new C();
MyClass d = new D();

Quand tu pourras écrire ça :

MyClass a = new MyClass("A");
MyClass b = new MyClass("B");
MyClass c = new MyClass("C");
MyClass d = new MyClass("D");

Si je devais modifier la signature de la méthode du constructeur de la BaseClass, je devrais modifier toutes les sous-classes.

C'est pourquoi l'héritage est l'artefact qui crée un couplage élevé, ce qui est indésirable dans les systèmes OO. Il devrait être évité et peut-être remplacé par la composition.

Réfléchissez si vous en avez vraiment besoin comme sous-classe. C'est pourquoi vous voyez très souvent des interfaces utilisées comme insted :

 public interface NameAware {
     public String getName();
 }

 class A implements NameAware ...
 class B implements NameAware ...
 class C ... etc. 

Ici, B et C auraient pu hériter de A, ce qui aurait créé un couplage très ÉLEVÉ entre elles, en utilisant des interfaces le couplage est réduit, si A décide qu'il ne sera plus "NameAware" les autres classes ne seront pas cassées.

Bien sûr, si vous voulez réutiliser le comportement, cela ne fonctionnera pas.

2 votes

Oui, sauf que vous ne pouvez plus vous assurer que vos instances sont initialisées correctement (c'est-à-dire qu'elles ont des noms dans ce cas particulier).

0 votes

@ChssPly76 : Oui, mais c'est probablement parce que l'héritage est mal utilisé. J'ai élargi ma réponse pour le couvrir.

1voto

YOUNG Points 31

" Soit vous définissez un constructeur sans argument dans une super classe, soit vous appelez super(n) comme première instruction de vos constructeurs dans la sous-classe. "

Je trouve cet article très utile : http://xahlee.info/java-a-day/inheritance_constructers.html

Regards,

P.S. - Je n'ai pas pu laisser de commentaire parce que je manque de réputation. Alors à la place, je l'écris comme une réponse.

0voto

Carlos Heuberger Points 11804

Votre BaseClass a besoin d'un someString donc livrer uno.
Essayez ça :

abstract public class BaseClass {
    String someString;
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public ASubClass() {
        super("someString");  // or a meaningfull value, same as getName()?
    }
    public String getName() {
        return "name value for ASubClass";
    }
}

o

abstract public class BaseClass {
    String someString;
    protected BaseClass() {  // for subclasses
        this.someString = null;  // or a meaningfull value
    }
    public BaseClass(String someString) {
        this.someString = someString;
    }
    abstract public String getName();
}

public class ACSubClass extends BaseClass {
    public String getName() {
        return "name value for ASubClass";
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X