Saya memiliki beberapa kode Java sederhana yang terlihat mirip dengan ini dalam strukturnya:
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";
}
}
Saya akan memiliki beberapa subclass BaseClass
, masing-masing menerapkan getName()
metode dengan caranya sendiri ( pola metode template ).
Ini bekerja dengan baik, tapi saya tidak suka memiliki konstruktor redundan di subclass. Ini lebih banyak untuk mengetik dan sulit untuk dipertahankan. Jika saya mengubah tanda tangan metode BaseClass
konstruktor, saya harus mengubah semua subclass.
Ketika saya menghapus konstruktor dari subclass, saya mendapatkan kesalahan waktu kompilasi ini:
Implicit super constructor BaseClass() is undefined for default constructor. Must define an explicit constructor
Apakah yang saya coba lakukan mungkin?
java
inheritance
dry
boilerplate
Joel
sumber
sumber
Jawaban:
Anda mendapatkan kesalahan ini karena kelas yang tidak memiliki konstruktor memiliki konstruktor default , yang tanpa argumen dan setara dengan kode berikut:
public ACSubClass() { super(); }
Namun karena BaseClass Anda mendeklarasikan sebuah konstruktor (dan oleh karena itu tidak memiliki konstruktor default, tanpa
super();
argumen yang akan disediakan oleh kompiler) ini ilegal - kelas yang memperluas BaseClass tidak dapat memanggil karena tidak ada konstruktor tanpa argumen di BaseClass.Ini mungkin sedikit kontra-intuitif karena Anda mungkin berpikir bahwa subclass secara otomatis memiliki konstruktor apa pun yang dimiliki kelas dasar.
Cara termudah untuk menyiasatinya adalah dengan kelas dasar untuk tidak mendeklarasikan konstruktor (dan karenanya memiliki konstruktor default, no-arg) atau memiliki konstruktor no-arg yang dideklarasikan (baik dengan sendirinya atau bersama konstruktor lain). Tetapi seringkali pendekatan ini tidak dapat diterapkan - karena Anda memerlukan argumen apa pun yang diteruskan ke konstruktor untuk membuat instance kelas yang sah.
sumber
BaseClass
tetapi buat itu hanya membuangUnsupportedOperationException
atau sesuatu. Ini bukan solusi terbaik (ini secara keliru menyarankan bahwa kelas dapat mendukung konstruktor no-arg), tetapi itu yang terbaik yang dapat saya pikirkan.Bagi mereka yang Google atas kesalahan ini dan tiba di sini: mungkin ada alasan lain untuk menerimanya. Eclipse memberikan kesalahan ini ketika Anda memiliki pengaturan proyek - konfigurasi sistem tidak cocok.
Misalnya, jika Anda mengimpor proyek Java 1.7 ke Eclipse dan Anda tidak memiliki 1.7 yang diatur dengan benar, Anda akan mendapatkan kesalahan ini. Kemudian Anda bisa pergi ke
Project - Preference - Java - Compiler
danswitch to 1.6 or earlier
; atau bukaWindow - Preferences - Java - Installed JREs
dan tambahkan / perbaiki instalasi JRE 1.7 Anda.sumber
Itu mungkin tetapi tidak seperti yang Anda miliki.
Anda harus menambahkan konstruktor no-args ke kelas dasar dan hanya itu!
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"; } }
Ketika Anda tidak menambahkan konstruktor (apa saja) ke kelas, kompilator menambahkan konstruktor default no arg untuk Anda.
Ketika defualt no arg memanggil super (); dan karena Anda tidak memilikinya di kelas super, Anda mendapatkan pesan kesalahan itu.
Itu tentang pertanyaan itu sendiri.
Sekarang, memperluas jawabannya:
Apakah Anda sadar bahwa membuat subclass (perilaku) untuk menentukan nilai (data) yang berbeda tidak masuk akal ?? !!! Saya harap Anda melakukannya.
Jika satu-satunya hal yang berubah adalah "nama" maka satu kelas parametrized sudah cukup!
Jadi Anda tidak membutuhkan ini:
MyClass a = new A("A"); MyClass b = new B("B"); MyClass c = new C("C"); MyClass d = new D("D");
atau
MyClass a = new A(); // internally setting "A" "B", "C" etc. MyClass b = new B(); MyClass c = new C(); MyClass d = new D();
Kapan Anda bisa menulis ini:
MyClass a = new MyClass("A"); MyClass b = new MyClass("B"); MyClass c = new MyClass("C"); MyClass d = new MyClass("D");
Itulah mengapa pewarisan adalah artefak yang menciptakan kopling TINGGI, yang tidak diinginkan dalam sistem OO. Ini harus dihindari dan mungkin diganti dengan komposisi.
Pikirkan jika Anda benar-benar membutuhkannya sebagai subclass. Itulah mengapa Anda sering melihat antarmuka yang digunakan insted:
public interface NameAware { public String getName(); } class A implements NameAware ... class B implements NameAware ... class C ... etc.
Di sini B dan C bisa mewarisi dari A yang akan menciptakan kopling yang sangat TINGGI di antara mereka, dengan menggunakan antarmuka kopling dikurangi, jika A memutuskan itu tidak lagi menjadi "NameAware" kelas lain tidak akan rusak.
Tentu saja, jika Anda ingin menggunakan kembali perilaku ini tidak akan berhasil.
sumber
Anda juga bisa mendapatkan kesalahan ini jika JRE tidak disetel. Jika demikian, coba tambahkan JRE System Library ke proyek Anda.
Di bawah Eclipse IDE:
sumber
Cara lain adalah memanggil super () dengan argumen yang diperlukan sebagai pernyataan pertama dalam konstruktor kelas turunan.
public class Sup { public Sup(String s) { ...} } public class Sub extends Sup { public Sub() { super("hello"); .. } }
sumber
Eclipse akan memberikan kesalahan ini jika Anda tidak memiliki panggilan ke konstruktor kelas super sebagai pernyataan pertama dalam konstruktor subclass.
sumber
Maaf untuk necroposting tetapi menghadapi masalah ini hari ini. Untuk semua orang yang juga menghadapi masalah ini - salah satu kemungkinan alasannya - Anda tidak menelepon
super
pada metode baris pertama. Baris kedua, ketiga, dan lainnya mengaktifkan kesalahan ini. Panggilan super harus menjadi panggilan pertama dalam metode Anda. Dalam hal ini semuanya baik-baik saja.sumber
Saya telah menyelesaikan masalah di atas sebagai berikut:
sumber
Anda dapat mengatasi kesalahan ini dengan menambahkan konstruktor tanpa argumen ke kelas dasar (seperti yang ditunjukkan di bawah).
Bersulang.
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"; } }
sumber
someString
) set dan karenanya secara total mengalahkan tujuan sebagai konstruktor.Saya mengalami kesalahan ini dan memperbaikinya dengan menghapus pengecualian yang dilemparkan dari samping metode ke blok coba / tangkap
Contoh: FROM:
public static HashMap<String, String> getMap() throws SQLException { }
UNTUK:
public static Hashmap<String,String> getMap() { try{ }catch(SQLException) { } }
sumber