Java-Fehler: Der implizite Superkonstruktor ist für den Standardkonstruktor nicht definiert

88

Ich habe einen einfachen Java-Code, der in seiner Struktur ähnlich aussieht:

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

Ich werde einige Unterklassen von haben BaseClass, von denen jede die getName()Methode auf ihre eigene Weise implementiert ( Muster der Vorlagenmethode ).

Das funktioniert gut, aber ich mag es nicht, den redundanten Konstruktor in den Unterklassen zu haben. Es ist mehr zu tippen und es ist schwierig zu pflegen. Wenn ich die Methodensignatur des BaseClassKonstruktors ändern würde, müsste ich alle Unterklassen ändern.

Wenn ich den Konstruktor aus den Unterklassen entferne, wird der folgende Fehler zur Kompilierungszeit angezeigt:

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

Ist das, was ich versuche, möglich?

Joel
quelle
1
Bitte verlassen Sie den 'redundanten' Konstruktor! Die Lesbarkeit Ihres Codes bleibt erhalten, und alle modernen IDEs können ihn automatisch erstellen, sodass Sie nur eine Verknüpfung eingeben müssen.
Andreas Dolk
3
Wenn ich ein Jahr später meine eigene Frage erneut lese, fällt mir ein, dass ich die Konstruktoren (einschließlich in der Basisklasse) wie von matt b vorgeschlagen hätte entfernen und dann eine statische Factory-Methode verwenden können, um Instanzen zu erstellen.
Joel

Antworten:

145

Sie erhalten diesen Fehler, weil eine Klasse ohne Konstruktor einen Standardkonstruktor hat , der ohne Argumente ist und dem folgenden Code entspricht:

public ACSubClass() {
    super();
}

Da Ihre BaseClass jedoch einen Konstruktor deklariert (und daher nicht den Standardkonstruktor super();ohne Argumente hat , den der Compiler sonst bereitstellen würde), ist dies unzulässig - eine Klasse, die BaseClass erweitert, kann nicht aufgerufen werden, da es keinen Konstruktor ohne Argumente gibt in BaseClass.

Dies ist wahrscheinlich ein wenig kontraintuitiv, da Sie vielleicht denken, dass eine Unterklasse automatisch einen Konstruktor hat, über den die Basisklasse verfügt.

Der einfachste Weg, dies zu umgehen, besteht darin, dass die Basisklasse keinen Konstruktor deklariert (und daher den Standardkonstruktor no-arg hat) oder einen deklarierten Konstruktor no-arg hat (entweder für sich oder zusammen mit anderen Konstruktoren). Oft kann dieser Ansatz jedoch nicht angewendet werden, da Sie alle Argumente benötigen, die an den Konstruktor übergeben werden, um eine legitime Instanz der Klasse zu erstellen.

matt b
quelle
17
"Dies ist wahrscheinlich ein wenig kontraintuitiv, da Sie vielleicht denken, dass eine Unterklasse automatisch einen Konstruktor hat, über den die Basisklasse verfügt." +1
Mr_and_Mrs_D
2
Aus Gründen der Nachwelt werde ich meine Lösung für zukünftige Leser vorschlagen: Erstellen Sie einen Konstruktor ohne Argumente, BaseClassaber lassen Sie ihn einfach einen UnsupportedOperationExceptionoder etwas werfen . Es ist nicht die beste Lösung (es deutet fälschlicherweise darauf hin, dass die Klasse einen Konstruktor ohne Argumente unterstützen kann), aber es ist die beste, die ich mir vorstellen kann.
JMTyler
48

Für diejenigen, die nach diesem Fehler suchen und hier ankommen: Es kann einen anderen Grund geben, ihn zu erhalten. Eclipse gibt diesen Fehler aus, wenn Sie ein Projekt-Setup haben - die Systemkonfiguration stimmt nicht überein.

Wenn Sie beispielsweise ein Java 1.7-Projekt in Eclipse importieren und 1.7 nicht richtig eingerichtet haben, wird dieser Fehler angezeigt. Dann können Sie entweder zu Project - Preference - Java - Compilerund gehen switch to 1.6 or earlier; oder gehen Sie zu Window - Preferences - Java - Installed JREsund fügen Sie Ihre JRE 1.7-Installation hinzu / reparieren Sie sie.

MF.OX
quelle
2
Ich habe diesen Fehler ohne ersichtlichen Grund in Eclipse erhalten. Dann habe ich den Arbeitsbereich gereinigt (Menü Projekt -> Reinigen ...) und er ging weg.
Erickrf
7

Es ist möglich, aber nicht so, wie Sie es haben.

Sie müssen der Basisklasse einen Konstruktor ohne Argumente hinzufügen, und das war's!

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

Wenn Sie einer Klasse keinen Konstruktor (any) hinzufügen, fügt der Compiler den Standard-Konstruktor no arg für Sie hinzu.

Wenn das Defualt no arg zu super () aufruft; und da Sie es nicht in der Superklasse haben, erhalten Sie diese Fehlermeldung.

Das ist über die Frage selbst.

Erweitern Sie nun die Antwort:

Ist Ihnen bewusst, dass das Erstellen einer Unterklasse (Verhalten) zur Angabe eines anderen Wertes (Daten) keinen Sinn macht? !!! Ich hoffe du tust.

Wenn sich nur der "Name" ändert, reicht eine einzige parametrisierte Klasse aus!

Das brauchst du also nicht:

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

oder

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

Wenn Sie dies schreiben können:

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

Wenn ich die Methodensignatur des BaseClass-Konstruktors ändern würde, müsste ich alle Unterklassen ändern.

Deshalb ist Vererbung das Artefakt, das eine HOHE Kopplung erzeugt, was in OO-Systemen unerwünscht ist. Es sollte vermieden und vielleicht durch Komposition ersetzt werden.

Überlegen Sie, ob Sie sie wirklich wirklich als Unterklasse brauchen. Deshalb sehen Sie sehr oft verwendete Schnittstellen insted:

 public interface NameAware {
     public String getName();
 }



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

Hier könnten B und C von A geerbt haben, was eine sehr hohe Kopplung zwischen ihnen erzeugt hätte. Durch die Verwendung von Schnittstellen wird die Kopplung reduziert, wenn A entscheidet, dass es nicht mehr "NameAware" ist, werden die anderen Klassen nicht kaputt gehen.

Wenn Sie das Verhalten wiederverwenden möchten, funktioniert dies natürlich nicht.

OscarRyz
quelle
2
Ja, außer Sie können nicht mehr sicherstellen, dass Ihre Instanzen ordnungsgemäß initialisiert werden (z. B. haben Sie in diesem speziellen Fall Namen)
ChssPly76
@ ChssPly76: Ja, aber das liegt wahrscheinlich daran, dass die Vererbung schlecht genutzt wird. Ich habe meine Antwort erweitert, um sie abzudecken.
OscarRyz
2

Sie können diesen Fehler auch erhalten, wenn JRE nicht festgelegt ist. Versuchen Sie in diesem Fall , Ihrem Projekt die JRE-Systembibliothek hinzuzufügen .

Unter Eclipse IDE:

  1. Öffnen Sie das Menü Projekt -> Eigenschaften oder klicken Sie mit der rechten Maustaste auf Ihr Projekt im Paket-Explorer und wählen Sie Eigenschaften (Alt + Eingabetaste unter Windows, Befehl + I unter Mac).
  2. Klicken Sie auf Java Build Path dann Bibliotheken Registerkarte
  3. wählen ModulePath oder Classpath und Presse Bibliothek hinzufügen ... Schaltfläche
  4. Wählen Sie JRE System Library und klicken Sie auf Next
  5. Lassen Sie die Standard-JRE für den Arbeitsbereich ausgewählt (Sie können auch eine andere Option wählen) und klicken Sie auf Fertig stellen
  6. Drücken Sie schließlich Übernehmen und Schließen .
Yogesh Kumar
quelle
1

Eine andere Möglichkeit besteht darin, super () mit dem erforderlichen Argument als erste Anweisung im abgeleiteten Klassenkonstruktor aufzurufen.

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

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

Eclipse gibt diesen Fehler aus, wenn Sie den Superklassenkonstruktor nicht als erste Anweisung im Unterklassenkonstruktor aufrufen.

Sagar
quelle
0

Entschuldigen Sie die Nekropostierung, aber ich bin erst heute mit diesem Problem konfrontiert. Für alle, die ebenfalls mit diesem Problem konfrontiert sind - einer der möglichen Gründe -, rufen Sie nicht superin der ersten Zeile der Methode auf. Zweite, dritte und andere Zeilen lösen diesen Fehler aus. Call of Super sollte der allererste Aufruf in Ihrer Methode sein. In diesem Fall ist alles in Ordnung.

Serj.by
quelle
-1

Sie können diesen Fehler beheben, indem Sie der Basisklasse einen argumentlosen Konstruktor hinzufügen (siehe Abbildung unten).

Prost.

 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";
    }
}
BrainO2
quelle
Das macht es einfach, ungültige Objekte (solche ohne someString) zu konstruieren , und macht somit den Zweck als Konstruktor völlig zunichte.
Robert
-1

Ich hatte diesen Fehler und habe ihn behoben, indem ich eine ausgelöste Ausnahme neben der Methode in einen Try / Catch-Block entfernt habe

Zum Beispiel: FROM:

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

}

ZU:

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

  }catch(SQLException)
  { 
  }
}
Thomas Johnson
quelle
Diese Antwort hat nichts mit Compilerfehlern für einen fehlenden Konstruktor zu tun.
Robert