Kesalahan Java: Konstruktor super implisit tidak ditentukan untuk konstruktor default

89

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 BaseClasskonstruktor, 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?

Joel
sumber
1
Tolong, tinggalkan konstruktor 'redundan'! Ini menjaga keterbacaan kode Anda dan semua IDE modern dapat membuatnya secara otomatis, jadi Anda hanya perlu memasukkan pintasan.
Andreas Dolk
3
Membaca ulang pertanyaan saya setahun kemudian dan terpikir oleh saya bahwa saya bisa saja menghapus konstruktor (termasuk dalam kelas dasar) seperti yang disarankan matt b, dan kemudian menggunakan metode pabrik statis untuk membuat instance.
Joel

Jawaban:

146

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.

matt b
sumber
17
"Ini mungkin sedikit kontra-intuitif karena Anda mungkin berpikir bahwa subclass secara otomatis memiliki konstruktor apa pun yang dimiliki kelas dasar." +1
Mr_and_Mrs_D
2
Demi anak cucu, saya akan menyarankan solusi saya untuk pembaca di masa mendatang: buat konstruktor no-arg BaseClasstetapi buat itu hanya membuang UnsupportedOperationExceptionatau sesuatu. Ini bukan solusi terbaik (ini secara keliru menyarankan bahwa kelas dapat mendukung konstruktor no-arg), tetapi itu yang terbaik yang dapat saya pikirkan.
JMTyler
49

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 - Compilerdan switch to 1.6 or earlier; atau buka Window - Preferences - Java - Installed JREsdan tambahkan / perbaiki instalasi JRE 1.7 Anda.

MF.OX
sumber
2
Baru saja mendapat kesalahan ini tanpa alasan yang jelas di Eclipse. Kemudian saya membersihkan ruang kerja (menu Proyek -> Bersihkan ...) dan itu pergi.
erickrf
7

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

Jika saya mengubah tanda tangan metode konstruktor BaseClass, saya harus mengubah semua subclass.

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.

OscarRyz
sumber
2
Ya, kecuali Anda tidak dapat lagi memastikan bahwa instans Anda diinisialisasi dengan benar (mis. Memiliki nama dalam kasus khusus ini)
ChssPly76
@ ChssPly76: Ya, tapi itu mungkin karena warisan digunakan dengan cara yang buruk. Saya memperluas jawaban saya untuk menutupinya.
OscarRyz
4

Anda juga bisa mendapatkan kesalahan ini jika JRE tidak disetel. Jika demikian, coba tambahkan JRE System Library ke proyek Anda.

Di bawah Eclipse IDE:

  1. buka menu Project -> Properties , atau klik kanan pada project Anda di Package Explorer dan pilih Properties (Alt + Enter di Windows, Command + I di Mac)
  2. klik pada Java Build Path lalu tab Libraries
  3. memilih Modulepath atau Classpath dan tekan Add Library ... tombol
  4. pilih JRE System Library lalu klik Next
  5. biarkan Workspace default JRE dipilih (Anda juga dapat mengambil opsi lain) dan klik Selesai
  6. terakhir tekan Apply dan Close .
yogesh kumar
sumber
2

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"); .. }
}
pengguna2407102
sumber
0

Eclipse akan memberikan kesalahan ini jika Anda tidak memiliki panggilan ke konstruktor kelas super sebagai pernyataan pertama dalam konstruktor subclass.

Sagar
sumber
0

Maaf untuk necroposting tetapi menghadapi masalah ini hari ini. Untuk semua orang yang juga menghadapi masalah ini - salah satu kemungkinan alasannya - Anda tidak menelepon superpada 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.

Serj.by
sumber
0

Saya telah menyelesaikan masalah di atas sebagai berikut:

  1. Klik Proyek.
  2. klik pada properti> Java Build Path> Library> JRE System Library> Edit
  3. Pilih sistem default JRE Dan Selesai
  4. Terapkan dan tutup.
Uttam Pawar
sumber
-1

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";
    }
}
BrainO2
sumber
Itu membuatnya mudah untuk membangun objek yang tidak valid (yang tanpa someString) set dan karenanya secara total mengalahkan tujuan sebagai konstruktor.
Robert
-1

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)
  { 
  }
}
Thomas Johnson
sumber
Jawaban ini tidak ada hubungannya dengan kesalahan kompiler untuk konstruktor yang hilang.
Robert