Errore Java: il super costruttore implicito non è definito per il costruttore predefinito


88

Ho un semplice codice Java che sembra simile a questo nella sua struttura:

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

Avrò parecchie sottoclassi di BaseClass, ognuna delle quali implementa il getName()metodo a modo suo ( modello di metodo modello ).

Funziona bene, ma non mi piace avere il costruttore ridondante nelle sottoclassi. È più da scrivere ed è difficile da mantenere. Se dovessi cambiare la firma del metodo del BaseClasscostruttore, dovrei cambiare tutte le sottoclassi.

Quando rimuovo il costruttore dalle sottoclassi, ottengo questo errore in fase di compilazione:

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

Quello che sto cercando di fare è possibile?


1
Per favore, lascia il costruttore "ridondante"! Mantiene la leggibilità del codice e tutti gli IDE moderni possono crearlo automaticamente, quindi devi solo digitare una scorciatoia.
Andreas Dolk

3
Rileggendo la mia domanda un anno dopo, mi viene in mente che avrei potuto rimuovere i costruttori (inclusi nella classe base) come suggerito da matt b, e quindi utilizzare un metodo factory statico per creare istanze.
Joel

Risposte:


145

Ottieni questo errore perché una classe che non ha un costruttore ha un costruttore predefinito , che è privo di argomenti ed è equivalente al codice seguente:

public ACSubClass() {
    super();
}

Tuttavia, poiché la tua BaseClass dichiara un costruttore (e quindi non ha il costruttore predefinito, no-arg che il compilatore altrimenti fornirebbe) questo è illegale: una classe che estende BaseClass non può chiamare super();perché non c'è un costruttore senza argomenti in BaseClass.

Questo è probabilmente un po 'controintuitivo perché potresti pensare che una sottoclasse abbia automaticamente un costruttore che ha la classe base.

Il modo più semplice per aggirare questo problema è che la classe base non dichiari un costruttore (e quindi abbia il costruttore predefinito no-arg) o abbia un costruttore no-arg dichiarato (da solo o insieme a qualsiasi altro costruttore). Ma spesso questo approccio non può essere applicato, perché è necessario che gli argomenti vengano passati al costruttore per costruire un'istanza legittima della classe.


17
"Questo è probabilmente un po 'controintuitivo perché potresti pensare che una sottoclasse abbia automaticamente un costruttore che ha la classe base." +1
Mr_and_Mrs_D

2
Per il bene dei posteri, suggerirò la mia soluzione ai futuri lettori: creare un costruttore senza argomenti BaseClassma farlo semplicemente lanciare un UnsupportedOperationExceptiono qualcosa. Non è la soluzione migliore (suggerisce falsamente che la classe può supportare un costruttore senza argomenti), ma è la migliore a cui riesco a pensare.
JMTyler

49

Per coloro che Google per questo errore e arrivano qui: potrebbe esserci un altro motivo per riceverlo. Eclipse restituisce questo errore quando si dispone della configurazione del progetto: mancata corrispondenza della configurazione del sistema.

Ad esempio, se importi un progetto Java 1.7 in Eclipse e non hai 1.7 impostato correttamente, otterrai questo errore. Quindi puoi andare a Project - Preference - Java - Compilere switch to 1.6 or earlier; oppure vai a Window - Preferences - Java - Installed JREse aggiungi / correggi l'installazione di JRE 1.7.


2
Ho appena ricevuto questo errore senza motivo apparente in Eclipse. Quindi ho pulito l'area di lavoro (menu Progetto -> Pulisci ...) ed è andata via.
erickrf

7

È possibile ma non come l'hai fatto tu.

Devi aggiungere un costruttore senza argomenti alla classe base e il gioco è fatto!

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

Quando non aggiungi un costruttore (qualsiasi) a una classe, il compilatore aggiunge il costruttore predefinito no arg per te.

Quando il defualt no arg chiama super (); e poiché non lo hai nella super classe, ricevi quel messaggio di errore.

Si tratta della domanda in sé.

Ora, espandendo la risposta:

Sei consapevole che la creazione di una sottoclasse (comportamento) per specificare diverso un diverso valore (dati) non ha senso ?? !!! Spero che tu lo faccia.

Se l'unica cosa che cambia è il "nome" allora è sufficiente una sola classe parametrizzata!

Quindi non hai bisogno di questo:

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();

Quando puoi scrivere questo:

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

Se dovessi cambiare la firma del metodo del costruttore BaseClass, dovrei cambiare tutte le sottoclassi.

Ecco perché l'ereditarietà è l'artefatto che crea accoppiamento ALTO, che è indesiderabile nei sistemi OO. Dovrebbe essere evitato e forse sostituito con la composizione.

Pensa se davvero ne hai davvero bisogno come sottoclasse. Ecco perché vedi molto spesso le interfacce utilizzate invece:

 public interface NameAware {
     public String getName();
 }



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

Qui B e C potrebbero aver ereditato da A che avrebbe creato un accoppiamento molto ALTO tra loro, utilizzando interfacce l'accoppiamento è ridotto, se A decide che non sarà più "NameAware" le altre classi non si rompono.

Ovviamente, se vuoi riutilizzare il comportamento, questo non funzionerà.


2
Sì, tranne per il fatto che non è più possibile garantire che le istanze siano inizializzate correttamente (ad esempio, hanno nomi in questo caso particolare)
ChssPly76

@ ChssPly76: Sì, ma probabilmente è perché l'eredità viene utilizzata in modo scadente. Ho ampliato la mia risposta per coprirlo.
OscarRyz

4

Potresti anche ricevere questo errore quando JRE non è impostato. In tal caso, prova ad aggiungere la libreria di sistema JRE al tuo progetto.

Sotto Eclipse IDE:

  1. apri il menu Progetto -> Proprietà o fai clic con il pulsante destro del mouse sul tuo progetto in Esplora pacchetti e scegli Proprietà (Alt + Invio su Windows, Comando + I su Mac)
  2. fare clic su Percorso build Java, quindi sulla scheda Librerie
  3. scegliere ModulePath o classpath e premere Add Biblioteca ... pulsante
  4. selezionare JRE System Library, quindi fare clic su Avanti
  5. mantieni selezionato il JRE predefinito dell'area di lavoro (puoi anche scegliere un'altra opzione) e fai clic su Fine
  6. infine premere Applica e Chiudi .

2

Un altro modo è chiamare super () con l'argomento richiesto come prima istruzione nel costruttore della classe derivata.

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

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

0

Eclipse restituirà questo errore se non si dispone di una chiamata al costruttore della super classe come prima istruzione nel costruttore della sottoclasse.


0

Ci scusiamo per il necropost, ma ho affrontato questo problema solo oggi. Per tutti coloro che devono affrontare anche questo problema - una delle sue possibili ragioni - non chiami superalla prima riga di metodo. La seconda, la terza e altre righe generano questo errore. Call of super dovrebbe essere la prima chiamata nel tuo metodo. In questo caso va tutto bene.


-1

È possibile risolvere questo errore aggiungendo un costruttore senza argomenti alla classe base (come mostrato di seguito).

Saluti.

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

Ciò semplifica la costruzione di oggetti non validi (quelli senza someString) set e quindi vanifica totalmente lo scopo di come costruttore.
Robert

-1

Ho riscontrato questo errore e l'ho risolto rimuovendo un'eccezione generata da accanto al metodo a un blocco try / catch

Ad esempio: FROM:

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

}

PER:

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

  }catch(SQLException)
  { 
  }
}

Questa risposta non ha nulla a che fare con gli errori del compilatore per un costruttore mancante.
Robert
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.