Mam prosty kod Java, który wygląda podobnie do tego w swojej strukturze:
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";
}
}
Będę miał kilka podklas, z BaseClass
których każda implementuje getName()
metodę na swój własny sposób ( wzorzec metody szablonowej ).
Działa to dobrze, ale nie podoba mi się posiadanie redundantnego konstruktora w podklasach. To bardziej typowe i trudne do utrzymania. Gdybym miał zmienić sygnaturę metody BaseClass
konstruktora, musiałbym zmienić wszystkie podklasy.
Kiedy usuwam konstruktora z podklas, otrzymuję ten błąd w czasie kompilacji:
Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor
Czy to, co próbuję zrobić, jest możliwe?
java
inheritance
dry
boilerplate
Joel
źródło
źródło
Odpowiedzi:
Ten błąd pojawia się, ponieważ klasa, która nie ma konstruktora, ma domyślny konstruktor, który nie zawiera argumentów i jest odpowiednikiem następującego kodu:
public ACSubClass() { super(); }
Jednak ponieważ twoja BaseClass deklaruje konstruktor (i dlatego nie ma domyślnego konstruktora bezargumentowego, który w przeciwnym razie dostarczyłby kompilator) jest to nielegalne - klasa, która rozszerza BaseClass, nie może wywołać,
super();
ponieważ nie ma konstruktora bez argumentów w BaseClass.Jest to prawdopodobnie trochę sprzeczne z intuicją, ponieważ można by pomyśleć, że podklasa automatycznie ma dowolnego konstruktora, który ma klasa bazowa.
Najprostszym sposobem obejścia tego problemu jest to, że klasa bazowa nie deklaruje konstruktora (i tym samym ma domyślny konstruktor bez argonu) lub ma zadeklarowany konstruktor bez argumentu (samodzielnie lub wraz z innymi konstruktorami). Ale często tego podejścia nie można zastosować - ponieważ potrzebujesz wszelkich argumentów, które są przekazywane do konstruktora, aby skonstruować prawidłową instancję klasy.
źródło
BaseClass
ale spraw, aby po prostu rzuciłUnsupportedOperationException
lub coś. To nie jest najlepsze rozwiązanie (fałszywie sugeruje, że klasa może obsługiwać konstruktor bez argonu), ale jest najlepszym, o jakim przychodzi mi do głowy.Dla tych, którzy wygooglują ten błąd i przybywają tutaj: może być inny powód, dla którego go otrzymali. Eclipse podaje ten błąd, gdy masz konfigurację projektu - niezgodność konfiguracji systemu.
Na przykład, jeśli importujesz projekt Java 1.7 do Eclipse i nie masz poprawnie skonfigurowanego 1.7, pojawi się ten błąd. Następnie możesz przejść do
Project - Preference - Java - Compiler
iswitch to 1.6 or earlier
; lub przejdź doWindow - Preferences - Java - Installed JREs
i dodaj / napraw instalację JRE 1.7.źródło
Jest to możliwe, ale nie tak, jak masz.
Musisz dodać konstruktor no-args do klasy bazowej i to wszystko!
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"; } }
Gdy nie dodasz konstruktora (żadnego) do klasy, kompilator doda domyślny konstruktor no arg.
Gdy defualt no arg wywołuje super (); a ponieważ nie masz go w super klasie, otrzymasz ten komunikat o błędzie.
Chodzi o samo pytanie.
Teraz rozszerzając odpowiedź:
Czy zdajesz sobie sprawę, że tworzenie podklasy (zachowania) w celu określenia innej wartości (danych) nie ma sensu ?? !!! Mam nadzieję, że tak.
Jeśli jedyną zmianą jest "nazwa", to wystarczy jedna sparametryzowana klasa!
Więc nie potrzebujesz tego:
MyClass a = new A("A"); MyClass b = new B("B"); MyClass c = new C("C"); MyClass d = new D("D");
lub
MyClass a = new A(); // internally setting "A" "B", "C" etc. MyClass b = new B(); MyClass c = new C(); MyClass d = new D();
Kiedy możesz to napisać:
MyClass a = new MyClass("A"); MyClass b = new MyClass("B"); MyClass c = new MyClass("C"); MyClass d = new MyClass("D");
Cóż, dlatego dziedziczenie jest artefaktem, który tworzy WYSOKIE sprzężenie, co jest niepożądane w systemach OO. Należy tego unikać i być może zastąpić kompozycją.
Pomyśl, czy naprawdę potrzebujesz ich jako podklasy. Dlatego bardzo często widzisz interfejsy używane zamiast:
public interface NameAware { public String getName(); } class A implements NameAware ... class B implements NameAware ... class C ... etc.
Tutaj B i C mogliby odziedziczyć po A, co stworzyłoby wśród nich bardzo WYSOKIE sprzężenie, przy użyciu interfejsów sprzężenie jest zredukowane, jeśli A zdecyduje, że nie będzie już „NameAware”, inne klasy nie zostaną zerwane.
Oczywiście, jeśli chcesz ponownie użyć zachowania, to nie zadziała.
źródło
Ten błąd może się również pojawić, gdy środowisko JRE nie jest ustawione. Jeśli tak, spróbuj dodać bibliotekę systemową JRE do swojego projektu.
W Eclipse IDE:
źródło
Innym sposobem jest wywołanie super () z wymaganym argumentem jako pierwszą instrukcją w konstruktorze klasy pochodnej.
public class Sup { public Sup(String s) { ...} } public class Sub extends Sup { public Sub() { super("hello"); .. } }
źródło
Eclipse poda ten błąd, jeśli nie masz wywołania konstruktora superklasy jako pierwszej instrukcji w konstruktorze podklasy.
źródło
Przepraszamy za nekroposty, ale właśnie dzisiaj napotkałem ten problem. Dla każdego, kto również boryka się z tym problemem - jednym z możliwych powodów - nie wywołujesz
super
pierwszej linii metody. Po drugie, trzecia i inne linie wywołują ten błąd. Call of super powinno być pierwszym wywołaniem w Twojej metodzie. W tym przypadku wszystko jest w porządku.źródło
Powyższy problem rozwiązałem w następujący sposób:
źródło
Możesz rozwiązać ten błąd, dodając konstruktor bez argumentów do klasy bazowej (jak pokazano poniżej).
Twoje zdrowie.
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"; } }
źródło
someString
) zestawu, a tym samym całkowicie przeczy celowi konstruktora.Miałem ten błąd i naprawiłem go, usuwając wyrzucony wyjątek spoza metody do bloku try / catch
Na przykład: OD:
public static HashMap<String, String> getMap() throws SQLException { }
DO:
public static Hashmap<String,String> getMap() { try{ }catch(SQLException) { } }
źródło