2009-07-29 11 views
84

Ho un po 'di codice Java semplice che è simile a questo nella sua struttura:errore Java: implicito costruttore eccellente non è definito per costruttore di default

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ò un bel paio di sottoclassi di BaseClass, ogni attuazione del getName() metodo a suo modo (template method pattern).

Questo funziona bene, ma non mi piace avere il costruttore ridondante nelle sottoclassi. È più da digitare ed è difficile da mantenere. Se dovessi cambiare la firma del metodo del costruttore BaseClass, dovrei modificare tutte le sottoclassi.

Quando rimuovo il costruttore dalle sottoclassi, ottengo questo errore 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 tuo codice e tutti i moderni IDE possono crearlo automaticamente, quindi devi solo digitare una scorciatoia. –

+3

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

risposta

138

Si ottiene questo errore perché una classe che non ha un costruttore ha un predefinita costruttore, che è argomento-less ed è equivalente al seguente codice:

public ACSubClass() { 
    super(); 
} 

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

Questo è probabilmente un po 'contro-intuitivo perché si potrebbe pensare che una sottoclasse abbia automaticamente un costruttore che ha la classe base.

Il modo più semplice per aggirare questo è 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 ad altri costruttori). Ma spesso questo approccio non può essere applicato - perché è necessario che qualunque argomento venga passato al costruttore per costruire un'istanza legit della classe.

+16

"Questo è probabilmente un po 'contro-intuitivo perché si potrebbe pensare che una sottoclasse abbia automaticamente un costruttore che ha la classe base." +1 –

+1

Per motivi di posterità, suggerirò la mia soluzione per i futuri lettori: creare un costruttore no-arg in 'BaseClass', ma creare semplicemente un' UnsupportedOperationException' o qualcosa del genere. Non è la soluzione migliore (suggerisce erroneamente che la classe possa supportare un costruttore no-arg), ma è il meglio che riesco a pensare. – JMTyler

7

È possibile ma non come l'avete.

Devi aggiungere un costruttore no-args 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 si aggiunge un costruttore (qualsiasi) a una classe il compilatore aggiungere il valore predefinito non contructor arg per voi.

Quando il defualt no arg chiama a super(); e dal momento che non ce l'hai nella super classe ricevi questo messaggio di errore.

Questa è la domanda.

Ora, ampliando la risposta:

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

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

Quindi non è necessario 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"); 

If I were to change the method signature of the BaseClass constructor, I would have to change all the subclasses.

Beh questo è il motivo per cui l'ereditarietà è l'artefatto quello crea l'accoppiamento ALTO, che è unde siribile nei sistemi OO. Dovrebbe essere evitato e forse sostituito con la composizione.

Pensa se davvero ne hai davvero bisogno come sottoclasse. Ecco perché si vede molto spesso interfacce utilizzate insted:

public interface NameAware { 
    public String getName(); 
} 



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

Qui B e C potrebbero hanno ereditato da A, che avrebbe creato un livello molto alto di accoppiamento tra loro, utilizzando le interfacce l'accoppiamento è ridotto, se A decide lo farà non sarà più "NameAware", le altre classi non si romperanno.

Ovviamente, se si desidera riutilizzare il comportamento, questo non funzionerà.

+2

Sì, tranne che non è più possibile garantire che le istanze siano inizializzate correttamente (ad esempio, in questo caso particolare) – ChssPly76

+0

@ ChssPly76: Sì, ma probabilmente perché l'ereditarietà viene utilizzata in modo non corretto. Ho ampliato la mia risposta per coprirlo. – OscarRyz

0

il tuo BaseClass ha bisogno di un poString così consegnare uno.
Prova questa:

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

Per coloro che Google per questo errore e arrivano qui: ci potrebbe essere un altro motivo per riceverla. Eclipse restituisce questo errore quando si dispone dell'impostazione del progetto - mancata corrispondenza nella configurazione del sistema.

Ad esempio, se si importa il progetto Java 1.7 in Eclipse e non si dispone di 1.7 correttamente configurato, si otterrà questo errore. Quindi puoi andare a Project - Preference - Java - Compiler e switch to 1.6 or earlier; oppure vai a Window - Preferences - Java - Installed JREs e aggiungi/correggi l'installazione di JRE 1.7.

+1

Ho appena ricevuto questo errore senza motivo apparente in Eclipse. Quindi ho pulito lo spazio di lavoro (menu Progetto -> Pulisci ...) e se ne è andato. – erickrf

-1

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

Cheers.

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

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

0

Un altro modo è chiamare super() con l'argomento richiesto come prima istruzione nel costruttore di classi derivate.

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

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

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

-1

ho avuto questo errore e ha riparato rimuovendo un'eccezione generata dal lato del metodo ad un blocco try/catch

Ad esempio: DA:

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

} 

TO:

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

    }catch(SQLException) 
    { 
    } 
} 
+0

Questa risposta non ha nulla a che fare con gli errori del compilatore per un costruttore mancante. – Robert

1

questo errore è dovuto a JRE non è stato impostato quindi si prega di seguire questi passi:


1. right clic Progetto k -> Proprietà -> Java Build Path -> Fare clic sulla scheda Librerie
2. Fare clic su Aggiungi libreria
3. Selezionare JRE Sistema Bibliotecario -> Fare clic su Avanti
4. scegliere Area di lavoro jre predefinito o JRE installata alternativo
5. click finish

+0

Gosh, l'OP non ha nemmeno detto quale IDE (se esiste) sta usando ... – Robert

0

Scusate per la necropostazione ma affrontato questo problema proprio oggi. Per tutti coloro che affrontano questo problema, uno dei possibili motivi, non si chiama super alla prima riga del metodo. La seconda, la terza e le altre linee attivano questo errore. Call of super dovrebbe essere la prima chiamata nel tuo metodo. In questo caso è tutto a posto.

Problemi correlati