ข้อผิดพลาด Java: Implicit super constructor ไม่ได้กำหนดไว้สำหรับตัวสร้างเริ่มต้น


89

ฉันมีโค้ด Java ง่ายๆที่มีลักษณะคล้ายกับสิ่งนี้ในโครงสร้าง:

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

ฉันจะมีคลาสย่อยไม่กี่คลาสBaseClassแต่ละคลาสใช้getName()วิธีการในแบบของตัวเอง ( รูปแบบวิธีเทมเพลต )

สิ่งนี้ใช้งานได้ดี แต่ฉันไม่ชอบให้ตัวสร้างซ้ำซ้อนในคลาสย่อย พิมพ์มากกว่าและดูแลรักษายาก ถ้าฉันจะเปลี่ยนเมธอดซิกเนเจอร์ของคอนBaseClassสตรัคเตอร์ฉันจะต้องเปลี่ยนคลาสย่อยทั้งหมด

เมื่อฉันลบตัวสร้างออกจากคลาสย่อยฉันได้รับข้อผิดพลาดเวลาคอมไพล์:

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

สิ่งที่ฉันพยายามทำนั้นเป็นไปได้หรือไม่?


1
กรุณาปล่อยให้ตัวสร้าง 'ซ้ำซ้อน'! มันรักษาความสามารถในการอ่านรหัสของคุณและ IDE สมัยใหม่ทั้งหมดสามารถสร้างได้โดยอัตโนมัติดังนั้นคุณเพียงแค่ต้องกดคีย์ลัด
Andreas Dolk

3
อ่านคำถามของตัวเองอีกครั้งในอีกหนึ่งปีต่อมาและเกิดขึ้นกับฉันว่าฉันสามารถลบคอนสตรัคเตอร์ (รวมในคลาสพื้นฐาน) ได้เหมือนที่ Matt b แนะนำแล้วใช้วิธีการโรงงานแบบคงที่เพื่อสร้างอินสแตนซ์
Joel

คำตอบ:


146

คุณได้รับข้อผิดพลาดนี้เนื่องจากคลาสที่ไม่มีตัวสร้างมีตัวสร้างเริ่มต้นซึ่งไม่มีอาร์กิวเมนต์และเทียบเท่ากับรหัสต่อไปนี้:

public ACSubClass() {
    super();
}

อย่างไรก็ตามเนื่องจาก BaseClass ของคุณประกาศตัวสร้าง (ดังนั้นจึงไม่มีค่าเริ่มต้นตัวสร้างไม่มีอาร์กิวเมนต์ที่คอมไพลเลอร์จะจัดเตรียมให้) สิ่งนี้ผิดกฎหมาย - คลาสที่ขยาย BaseClass ไม่สามารถเรียกได้super();เนื่องจากไม่มีตัวสร้างที่ไม่มีอาร์กิวเมนต์ ใน BaseClass

นี่อาจจะใช้งานง่ายเล็กน้อยเนื่องจากคุณอาจคิดว่าคลาสย่อยมีตัวสร้างใด ๆ ที่คลาสพื้นฐานมีอยู่โดยอัตโนมัติ

วิธีที่ง่ายที่สุดในการแก้ปัญหานี้คือสำหรับคลาสฐานที่จะไม่ประกาศตัวสร้าง (ดังนั้นจึงมีค่าเริ่มต้นตัวสร้างไม่มีอาร์กิวเมนต์) หรือมีตัวสร้างไม่มีอาร์กิวเมนต์ที่ประกาศไว้ (ไม่ว่าจะด้วยตัวเองหรือควบคู่ไปกับตัวสร้างอื่น ๆ ) แต่บ่อยครั้งวิธีนี้ไม่สามารถนำไปใช้ - เพราะคุณต้องการอาร์กิวเมนต์ใด ๆ ที่ส่งผ่านไปยังตัวสร้างเพื่อสร้างอินสแตนซ์ที่ถูกต้องของคลาส


17
"นี่อาจจะใช้งานง่ายเล็กน้อยเพราะคุณอาจคิดว่าคลาสย่อยมีตัวสร้างที่คลาสพื้นฐานมีอยู่โดยอัตโนมัติ" +1
Mr_and_Mrs_D

2
เพื่อประโยชน์ของลูกหลานฉันจะแนะนำวิธีแก้ปัญหาของฉันสำหรับผู้อ่านในอนาคต: สร้างตัวสร้างที่ไม่มีข้อโต้แย้งBaseClassแต่ทำให้เพียงแค่โยนUnsupportedOperationExceptionหรือบางสิ่งบางอย่าง ไม่ใช่วิธีแก้ปัญหาที่ดีที่สุด (แนะนำอย่างผิด ๆ ว่าคลาสสามารถรองรับคอนสตรัคเตอร์ที่ไม่มีอาร์กิวเมนต์) แต่เป็นวิธีที่ดีที่สุดที่ฉันคิดได้
JMTyler

51

สำหรับผู้ที่ Google ทราบถึงข้อผิดพลาดนี้และมาถึงที่นี่อาจมีสาเหตุอื่นที่ได้รับ Eclipse แสดงข้อผิดพลาดนี้เมื่อคุณตั้งค่าโปรเจ็กต์ - การกำหนดค่าระบบไม่ตรงกัน

ตัวอย่างเช่นหากคุณอิมพอร์ตโปรเจ็กต์ Java 1.7 ไปยัง Eclipse และคุณไม่ได้ตั้งค่า 1.7 อย่างถูกต้องคุณจะได้รับข้อผิดพลาดนี้ จากนั้นคุณสามารถไปที่Project - Preference - Java - Compilerและswitch to 1.6 or earlier; หรือไปที่Window - Preferences - Java - Installed JREsและเพิ่ม / แก้ไขการติดตั้ง JRE 1.7 ของคุณ


2
เพิ่งได้รับข้อผิดพลาดนี้โดยไม่มีเหตุผลชัดเจนใน Eclipse จากนั้นฉันทำความสะอาดพื้นที่ทำงาน (เมนู Project -> Clean ... ) และมันก็หายไป
erickrf

7

เป็นไปได้ แต่ไม่ใช่ในแบบที่คุณมี

คุณต้องเพิ่มตัวสร้าง no-args ให้กับคลาสพื้นฐานและนั่นแหล่ะ!

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

เมื่อคุณไม่ได้เพิ่มคอนสตรัคเตอร์ (ใด ๆ ) ในคลาสคอมไพลเลอร์จะเพิ่มตัวสร้างอาร์กิวเมนต์เริ่มต้นให้กับคุณ

เมื่อ defualt no arg เรียก super (); และเนื่องจากคุณไม่มีในคลาสระดับสูงคุณจึงได้รับข้อความแสดงข้อผิดพลาดนั้น

นั่นคือคำถามเกี่ยวกับตัวมันเอง

ตอนนี้ขยายคำตอบ:

คุณทราบหรือไม่ว่าการสร้างคลาสย่อย (พฤติกรรม) เพื่อระบุค่าที่แตกต่างกัน (ข้อมูล) ไม่สมเหตุสมผล ?? !!! ฉันหวังว่าคุณจะทำ

หากสิ่งเดียวที่เปลี่ยนแปลงคือ "ชื่อ" ดังนั้นพารามีทรีคลาสเดียวก็เพียงพอแล้ว!

ดังนั้นคุณไม่ต้องการสิ่งนี้:

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

หรือ

MyClass a = new A(); // internally setting "A" "B", "C" etc.
MyClass b = new B();
MyClass c = new C();
MyClass d = new D();

เมื่อคุณสามารถเขียนสิ่งนี้:

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

ถ้าฉันจะเปลี่ยนลายเซ็นวิธีการของตัวสร้าง BaseClass ฉันจะต้องเปลี่ยนคลาสย่อยทั้งหมด

นั่นคือเหตุผลที่การถ่ายทอดทางพันธุกรรมเป็นสิ่งประดิษฐ์ที่สร้างการมีเพศสัมพันธ์สูงซึ่งไม่เป็นที่ต้องการในระบบ OO ควรหลีกเลี่ยงและอาจแทนที่ด้วยองค์ประกอบ

คิดว่าคุณต้องการมันเป็นคลาสย่อยจริงๆหรือไม่ นั่นเป็นเหตุผลที่คุณเห็นอินเทอร์เฟซที่ใช้บ่อยมาก:

 public interface NameAware {
     public String getName();
 }



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

ที่นี่ B และ C อาจได้รับการสืบทอดมาจาก A ซึ่งจะสร้างการเชื่อมต่อที่สูงมากในหมู่พวกเขาโดยการใช้อินเตอร์เฟสการเชื่อมต่อจะลดลงถ้า A ตัดสินใจว่าจะไม่เป็น "NameAware" อีกต่อไปคลาสอื่น ๆ จะไม่พัง

แน่นอนว่าหากคุณต้องการใช้พฤติกรรมซ้ำสิ่งนี้จะไม่ได้ผล


2
ใช่ยกเว้นคุณไม่สามารถมั่นใจได้อีกต่อไปว่าอินสแตนซ์ของคุณเริ่มต้นอย่างถูกต้อง (เช่นมีชื่อในกรณีนี้โดยเฉพาะ)
ChssPly76

@ ChssPly76: ใช่ แต่นั่นอาจเป็นเพราะมรดกถูกใช้ไปในทางที่ไม่ดี ฉันขยายคำตอบให้ครอบคลุม
OscarRyz

4

คุณอาจได้รับข้อผิดพลาดนี้เมื่อไม่ได้ตั้งค่า JRE ในกรณีนี้ให้ลองเพิ่มJRE System Libraryในโปรเจ็กต์ของคุณ

ภายใต้ Eclipse IDE:

  1. เปิดเมนูProject -> Propertiesหรือคลิกขวาที่โปรเจ็กต์ของคุณในPackage Explorerแล้วเลือกProperties (Alt + Enter บน Windows, Command + I บน Mac)
  2. คลิกที่Java Build Pathจากนั้นแท็บLibraries
  3. เลือกModulepathหรือClasspathและกดเพิ่มห้องสมุด ...ปุ่ม
  4. เลือกJRE System Libraryจากนั้นคลิกNext
  5. ให้JRE เริ่มต้นพื้นที่ทำงานที่เลือก (คุณยังสามารถใช้ตัวเลือกอื่น) และคลิกเสร็จสิ้น
  6. ในที่สุดก็กดApply และปิด

2

อีกวิธีหนึ่งคือเรียก super () ด้วยอาร์กิวเมนต์ที่ต้องการเป็นคำสั่งแรกในตัวสร้างคลาสที่ได้รับ

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

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

0

Eclipse จะให้ข้อผิดพลาดนี้หากคุณไม่ได้เรียกใช้ super class constructor เป็นคำสั่งแรกใน subclass constructor


0

ขออภัยสำหรับการตัดการโพสต์ แต่พบปัญหานี้ในวันนี้ สำหรับทุกคนที่ต้องเผชิญกับปัญหานี้ - หนึ่งในเหตุผลที่เป็นไปได้ - คุณอย่าเรียกsuperใช้วิธีการบรรทัดแรก บรรทัดที่สองสามและอื่น ๆ ทำให้เกิดข้อผิดพลาดนี้ Call of super ควรเป็นสายแรกในวิธีการของคุณ ในกรณีนี้ทุกอย่างเรียบร้อยดี


0

ฉันได้แก้ไขปัญหาข้างต้นแล้วดังนี้:

  1. คลิกที่โครงการ
  2. คลิกที่คุณสมบัติ> Java Build Path> Library> JRE System Library> Edit
  3. เลือกระบบเริ่มต้น JRE และเสร็จสิ้น
  4. สมัครและปิด

-1

คุณสามารถแก้ไขข้อผิดพลาดนี้ได้โดยการเพิ่มตัวสร้างแบบไม่มีอาร์กิวเมนต์ให้กับคลาสพื้นฐาน (ดังที่แสดงด้านล่าง)

ไชโย

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

ทำให้ง่ายต่อการสร้างวัตถุที่ไม่ถูกต้อง (วัตถุที่ไม่มีsomeString) ตั้งค่าและด้วยเหตุนี้จึงเอาชนะจุดประสงค์ของการเป็นตัวสร้างโดยสิ้นเชิง
Robert

-1

ฉันมีข้อผิดพลาดนี้และได้รับการแก้ไขโดยการลบข้อยกเว้นที่ถูกโยนออกจากข้างวิธีการไปยังบล็อก try / catch

ตัวอย่างเช่น: จาก:

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

}

ถึง:

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

  }catch(SQLException)
  { 
  }
}

คำตอบนี้ไม่เกี่ยวข้องกับข้อผิดพลาดของคอมไพเลอร์สำหรับตัวสร้างที่ขาดหายไป
Robert
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.