web-dev-qa-db-fra.com

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

J'ai un code Java simple qui ressemble à ceci dans sa structure:

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";
    }
}

J'aurai plusieurs sous-classes de BaseClass, chacune implémentant la méthode getName() à sa manière ( template method pattern ).

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 devais changer la signature de la méthode du constructeur BaseClass, je devrais changer toutes les sous-classes.

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

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

Est-ce que ce que j'essaie de faire est possible?

85
Joel

Vous obtenez cette erreur car une classe qui n'a pas de constructeur a un constructeur default , qui est sans argument et est équivalent au code suivant:

public ACSubClass() {
    super();
}

Cependant, puisque votre BaseClass déclare un constructeur (et n'a donc pas le constructeur par défaut, no-arg 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 d'argument no-argument constructeur dans BaseClass.

C'est probablement un peu contre-intuitif car vous pourriez penser qu'une sous-classe a automatiquement tout constructeur que possède la classe de base.

Le moyen le plus simple consiste à ne pas déclarer un constructeur (et donc le constructeur par défaut, no-arg) ou un constructeur no-arg déclaré (seul ou à côté de tout autre constructeur). Mais souvent, cette approche ne peut pas être appliquée car vous avez besoin de tous les arguments passés au constructeur pour construire une instance légitime de la classe.

140
matt b

Pour ceux qui recherchent cette erreur et arrivent ici: il pourrait y avoir une autre raison de la recevoir. Eclipse renvoie cette erreur en cas de conflit entre configuration du système et configuration du projet.

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

43
MF.OX

C'est possible mais pas comme vous l'avez.

Vous devez ajouter un constructeur no-args à 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 (aucun) à une classe, le compilateur ajoute pour vous le constructeur par défaut no arg.

Quand 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 à propos de la question elle-même. 

Maintenant, développant la réponse:

Etes-vous conscient que créer une sous-classe (comportement) pour spécifier différentes valeurs (données) n'a pas de sens ?? !!! J'espère que tu vas le faire.

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

Donc vous n’avez pas besoin de ça:

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

ou 

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

Quand vous pouvez écrire ceci:

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

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

Eh bien, c’est la raison pour laquelle l’héritage est l’artefact qui crée le couplage HIGH, indésirable dans les systèmes OO. Cela devrait être évité et peut-être remplacé par une composition.

Pensez si vous en avez vraiment besoin en tant que sous-classe. C'est pourquoi vous voyez très souvent les interfaces utilisées 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É. En utilisant des interfaces, le couplage est réduit. Si A décide de ne plus être "NameAware", les autres classes ne seront pas interrompues.

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

7
OscarRyz

Vous pouvez également obtenir cette erreur lorsque JRE n'est pas défini. Si c'est le cas, essayez d'ajouter JRE System Library à votre projet.

Sous Eclipse IDE:

  1. ouvrir le menu Projet -> Propriétés , ou cliquez avec le bouton droit de la souris sur votre projet dans Package Explorer et choisissez Propriétés (Alt + Entrée sous Windows, Commande + I sur Mac)
  2. cliquez sur Java Build Path then Libraries tab
  3. choisissez Modulepath ou Classpath et appuyez sur Ajouter une bibliothèque ... bouton
  4. sélectionnez JRE System Library puis cliquez sur Suivant
  5. garder JRE par défaut de Workspace sélectionné (vous pouvez également choisir une autre option) et cliquez sur Terminer
  6. enfin appuyez sur Appliquer et Fermer .
1
yogesh kumar

Eclipse donnera cette erreur si vous n’avez pas fait appel au constructeur de la super classe comme première instruction du constructeur de la sous-classe.

0
Sagar

votre BaseClass a besoin d'un someString pour deliver one.
Essaye ç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";
    }
}

ou 

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";
    }
}
0
Carlos Heuberger

Appelez super () avec l’argument requis comme première instruction dans le constructeur de la classe dérivée.

public class Sup {
    public Sup(String s) { ...}
}

public class Sub extends Sup {
    public Sub() { super("hello"); .. }
}
0
user2407102

Désolé pour le nécropostage, mais fait face à ce problème juste aujourd'hui. Pour tout le monde confronté également à ce problème - une des raisons possibles - vous n'appelez pas super à la première ligne de la méthode. Les lignes deux, trois et trois déclenchent cette erreur. Call of super devrait être le premier appel de votre méthode. Dans ce cas tout va bien.

0
Serj.by