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

88

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 pas mal de sous-classes de BaseClass, chacune implémentant la getName()méthode à sa manière ( modèle de méthode de modèle ).

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 méthode du BaseClassconstructeur, 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?

Joël
la source
1
S'il vous plaît, laissez le constructeur «redondant»! Il maintient la lisibilité de votre code et tous les IDE modernes peuvent le créer automatiquement, il vous suffit donc de saisir un raccourci.
Andreas Dolk
3
Relire ma propre question un an plus tard et il me vient à l'esprit que j'aurais pu supprimer les constructeurs (y compris dans la classe de base) comme le suggérait matt b, puis utiliser une méthode de fabrique statique pour construire des instances.
Joel

Réponses:

145

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

public ACSubClass() {
    super();
}

Cependant, puisque votre BaseClass déclare un constructeur (et n'a donc pas le constructeur par défaut, sans argument que le compilateur fournirait autrement), c'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.

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 de contourner cela est pour la classe de base de ne pas déclarer de constructeur (et donc d'avoir le constructeur par défaut, no-arg) ou d'avoir un constructeur sans argument déclaré (soit seul, soit à côté de tout autre constructeur). Mais souvent, cette approche ne peut pas être appliquée - car vous avez besoin des arguments passés au constructeur pour construire une instance légitime de la classe.

mat b
la source
17
"C'est probablement un peu contre-intuitif car vous pourriez penser qu'une sous-classe a automatiquement tout constructeur que la classe de base a." +1
Mr_and_Mrs_D
2
Pour le bien de la postérité, je suggérerai ma solution aux futurs lecteurs: créer un constructeur sans argument BaseClassmais le faire simplement lancer un UnsupportedOperationExceptionou quelque chose. Ce n'est pas la meilleure solution (cela suggère à tort que la classe peut supporter un constructeur sans argument), mais c'est la meilleure à laquelle je puisse penser.
JMTyler
49

Pour ceux qui recherchent cette erreur sur Google et arrivent ici: il pourrait y avoir une autre raison de la recevoir. Eclipse donne cette erreur lorsque vous avez une configuration de projet - incompatibilité de configuration du système.

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

MF.OX
la source
2
Je viens de recevoir cette erreur sans raison apparente dans Eclipse. Ensuite, j'ai nettoyé l'espace de travail (menu Projet -> Nettoyer ...) et il est parti.
erickrf
7

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 le constructeur par défaut no arg pour vous.

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

C'est à peu près la question en soi.

Maintenant, élargissez la réponse:

Etes-vous conscient que la création d'une sous-classe (comportement) pour spécifier une valeur différente (données) n'a aucun sens ?? !!! J'espère que tu vas le faire.

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

Vous n'avez donc pas besoin de ceci:

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 pourquoi l'héritage est l'artefact qui crée un couplage HIGH, ce qui n'est pas souhaitable dans les systèmes OO. Il devrait être évité et peut-être remplacé par la composition.

Pensez si vous en avez vraiment besoin en tant que sous-classe. C'est pourquoi vous voyez très souvent des interfaces utilisées instées:

 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 qui aurait créé un couplage très ÉLEVÉ entre eux, 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 souhaitez réutiliser un comportement, cela ne fonctionnera pas.

OscarRyz
la source
2
Oui, sauf que vous ne pouvez plus vous assurer que vos instances sont correctement initialisées (par exemple, avoir des noms dans ce cas particulier)
ChssPly76
@ ChssPly76: Oui, mais c'est probablement parce que l'héritage est mal utilisé. J'ai développé ma réponse pour la couvrir.
OscarRyz
4

Vous pouvez également obtenir cette erreur lorsque JRE n'est pas défini. Si tel est le cas, essayez d'ajouter la bibliothèque système JRE à votre projet.

Sous Eclipse IDE:

  1. ouvrez le menu Projet -> Propriétés , ou faites un clic droit sur votre projet dans l' Explorateur de packages et choisissez Propriétés (Alt + Entrée sous Windows, Commande + I sur Mac)
  2. cliquez sur Java Build Path puis sur l' onglet Libraries
  3. choisissez Modulepath ou Classpath et appuyez sur le bouton Ajouter une bibliothèque ...
  4. sélectionnez Bibliothèque système JRE puis cliquez sur Suivant
  5. garder le JRE par défaut de Workspace sélectionné (vous pouvez également prendre une autre option) et cliquer sur Terminer
  6. enfin appuyez sur Appliquer et Fermer .
yogesh kumar
la source
2

Une autre façon est d'appeler super () avec l'argument requis comme première instruction dans le constructeur de classe dérivée.

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

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

Eclipse donnera cette erreur si vous n'avez pas d'appel au constructeur de super classe comme première instruction dans le constructeur de sous-classe.

Sagar
la source
0

Désolé pour le nécropostage, mais j'ai rencontré ce problème aujourd'hui. Pour tous ceux qui sont également confrontés à ce problème - une des raisons possibles - vous n'appelez pas superà la première ligne de méthode. Les deuxième, troisième et autres lignes déclenchent cette erreur. L'appel de super devrait être le tout premier appel de votre méthode. Dans ce cas, tout va bien.

Serj.by
la source
-1

Vous pouvez résoudre cette erreur en ajoutant un constructeur sans argument à la classe de base (comme indiqué ci-dessous).

À votre santé.

 abstract public class BaseClass {
        // ADD AN ARGUMENTLESS CONSTRUCTOR TO THE BASE CLASS
        public 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";
    }
}
CerveauO2
la source
Cela facilite la construction d'objets non valides (ceux sans someString) set et donc va totalement à l'encontre de l'objectif de en tant que constructeur.
Robert
-1

J'ai eu cette erreur et je l'ai corrigée en supprimant une exception levée à côté de la méthode vers un bloc try / catch

Par exemple: FROM:

public static HashMap<String, String> getMap() throws SQLException
{

}

À:

public static Hashmap<String,String> getMap()
{
  try{

  }catch(SQLException)
  { 
  }
}
Thomas Johnson
la source
Cette réponse n'a rien à voir avec les erreurs du compilateur pour un constructeur manquant.
Robert