Lỗi Java: Hàm tạo siêu ngầm định không được xác định cho hàm tạo mặc định


88

Tôi có một số mã Java đơn giản trông giống với mã này trong cấu trúc của nó:

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

Tôi sẽ có khá nhiều lớp con BaseClass, mỗi lớp triển khai getName()phương thức theo cách riêng của nó ( mẫu phương thức mẫu ).

Điều này hoạt động tốt, nhưng tôi không thích có hàm tạo dư thừa trong các lớp con. Nó nhiều hơn để gõ và rất khó để bảo trì. Nếu tôi thay đổi chữ ký phương thức của hàm BaseClasstạo, tôi sẽ phải thay đổi tất cả các lớp con.

Khi tôi xóa phương thức khởi tạo khỏi các lớp con, tôi gặp lỗi thời gian biên dịch này:

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

Điều tôi đang cố gắng làm có khả thi không?


1
Vui lòng để lại hàm tạo 'dư thừa'! Nó duy trì khả năng đọc mã của bạn và tất cả các IDE hiện đại đều có thể tạo mã tự động, vì vậy bạn chỉ cần gõ một phím tắt.
Andreas Dolk,

3
Đọc lại câu hỏi của chính tôi một năm sau đó và tôi xảy ra với tôi rằng tôi có thể đã loại bỏ các hàm tạo (bao gồm cả trong lớp cơ sở) như matt b đã đề xuất, và sau đó sử dụng phương thức static factory để xây dựng các phiên bản.
Joel

Câu trả lời:


145

Bạn gặp lỗi này vì một lớp không có hàm tạo có một hàm tạo mặc định , hàm này ít đối số hơn và tương đương với đoạn mã sau:

public ACSubClass() {
    super();
}

Tuy nhiên, vì BaseClass của bạn khai báo một hàm tạo (và do đó không có hàm tạo mặc định, không có đối số mà trình biên dịch sẽ cung cấp) nên điều này là bất hợp pháp - một lớp mở rộng BaseClass không thể gọi super(); vì không có hàm tạo không đối số trong BaseClass.

Điều này có lẽ hơi phản trực quan vì bạn có thể nghĩ rằng một lớp con tự động có bất kỳ hàm tạo nào mà lớp cơ sở có.

Cách đơn giản nhất để giải quyết vấn đề này là để lớp cơ sở không khai báo một hàm tạo (và do đó có hàm tạo mặc định, không có đối số) hoặc có một hàm tạo không đối số được khai báo (tự nó hoặc cùng với bất kỳ hàm tạo nào khác). Nhưng thường thì cách tiếp cận này không thể được áp dụng - bởi vì bạn cần bất kỳ đối số nào đang được chuyển vào hàm tạo để tạo một thể hiện hợp pháp của lớp.


17
"Điều này có lẽ hơi phản trực quan vì bạn có thể nghĩ rằng một lớp con tự động có bất kỳ hàm tạo nào mà lớp cơ sở có." +1
Mr_and_Mrs_D

2
Vì lợi ích của hậu thế, tôi sẽ đề xuất giải pháp của mình cho những độc giả trong tương lai: tạo một hàm tạo không đối số BaseClassnhưng làm cho nó chỉ đơn giản là ném một UnsupportedOperationExceptionhoặc một cái gì đó. Đó không phải là giải pháp tốt nhất (nó gợi ý sai rằng lớp có thể hỗ trợ một phương thức khởi tạo no-arg), nhưng đó là giải pháp tốt nhất mà tôi có thể nghĩ đến.
JMTyler

49

Đối với những người Google cho lỗi này và đến đây: có thể có một lý do khác để nhận được nó. Eclipse đưa ra lỗi này khi bạn thiết lập dự án - cấu hình hệ thống không khớp.

Ví dụ: nếu bạn nhập dự án Java 1.7 vào Eclipse và bạn không thiết lập đúng 1.7 thì bạn sẽ gặp lỗi này. Sau đó, bạn có thể truy cập Project - Preference - Java - Compilerswitch to 1.6 or earlier; hoặc đi tới Window - Preferences - Java - Installed JREsvà thêm / sửa bản cài đặt JRE 1.7 của bạn.


2
Chỉ gặp lỗi này không có lý do rõ ràng trong Eclipse. Sau đó, tôi dọn dẹp không gian làm việc (menu Project -> Clean ...) và nó biến mất.
erickrf

7

Nó có thể nhưng không phải là cách bạn có nó.

Bạn phải thêm một hàm tạo no-args vào lớp cơ sở và thế là xong!

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

Khi bạn không thêm một hàm tạo (bất kỳ) vào một lớp, trình biên dịch sẽ thêm một hàm tạo không đối số mặc định cho bạn.

Khi defualt no arg gọi tới super (); và vì bạn không có nó trong lớp siêu cấp nên bạn nhận được thông báo lỗi đó.

Đó là về câu hỏi tự nó.

Bây giờ, mở rộng câu trả lời:

Bạn có biết rằng việc tạo một lớp con (hành vi) để chỉ định một giá trị (dữ liệu) khác không có ý nghĩa gì không ?? !!! Tôi hy vọng bạn làm.

Nếu điều duy nhất thay đổi là "tên" thì một lớp duy nhất được tham số hóa là đủ!

Vì vậy, bạn không cần điều này:

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

hoặc là

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

Khi bạn có thể viết điều này:

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

Nếu tôi thay đổi chữ ký phương thức của phương thức khởi tạo BaseClass, tôi sẽ phải thay đổi tất cả các lớp con.

Đó là lý do tại sao kế thừa là yếu tố tạo ra sự kết hợp CAO, điều không mong muốn trong các hệ thống OO. Nó nên được tránh và có lẽ được thay thế bằng thành phần.

Hãy nghĩ xem bạn có thực sự cần chúng dưới dạng lớp con không. Đó là lý do tại sao bạn thường thấy các giao diện được sử dụng chèn:

 public interface NameAware {
     public String getName();
 }



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

Ở đây B và C có thể được kế thừa từ A, điều này sẽ tạo ra một mối ghép rất CAO giữa chúng, bằng cách sử dụng các giao diện, sự ghép nối bị giảm đi, nếu A quyết định nó sẽ không còn là "NameAware" thì các lớp khác sẽ không bị phá vỡ.

Tất nhiên, nếu bạn muốn sử dụng lại hành vi này sẽ không hoạt động.


2
Vâng, ngoại trừ bạn không còn có thể đảm bảo rằng trường hợp của bạn được khởi động đúng (ví dụ có tên trong trường hợp đặc biệt này)
ChssPly76

@ ChssPly76: Đúng, nhưng đó có thể là do phần thừa kế đang được sử dụng một cách kém hiệu quả. Tôi mở rộng câu trả lời của mình để bao quát nó.
OscarRyz

4

Bạn cũng có thể gặp lỗi này khi JRE không được đặt. Nếu vậy, hãy thử thêm Thư viện hệ thống JRE vào dự án của bạn.

Trong IDE Eclipse:

  1. mở menu Dự án -> Thuộc tính hoặc nhấp chuột phải vào dự án của bạn trong Trình khám phá gói và chọn Thuộc tính (Alt + Enter trên Windows, Command + I trên Mac)
  2. nhấp vào Đường dẫn xây dựng Java sau đó nhấp vào Thư viện tab
  3. chọn Modulepath hoặc Classpath và nhấn Add Library ... nút
  4. chọn Thư viện Hệ thống JRE rồi nhấp vào Tiếp theo
  5. giữ JRE mặc định của Workspace được chọn (bạn cũng có thể chọn một tùy chọn khác) và nhấp vào Finish
  6. cuối cùng nhấn Áp dụng và Đóng .

2

Một cách khác là gọi super () với đối số bắt buộc như một câu lệnh đầu tiên trong hàm tạo lớp dẫn xuất.

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

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

0

Eclipse sẽ đưa ra lỗi này nếu bạn không có lệnh gọi đến hàm tạo siêu lớp như một câu lệnh đầu tiên trong hàm tạo lớp con.


0

Xin lỗi vì đã đăng tải nhưng phải đối mặt với vấn đề này hôm nay. Đối với tất cả mọi người cũng phải đối mặt với vấn đề này - một trong những lý do có thể xảy ra - bạn không gọi superở dòng đầu tiên của phương thức. Dòng thứ hai, thứ ba và các dòng khác gây ra lỗi này. Call of super phải là cuộc gọi đầu tiên trong phương thức của bạn. Trong trường hợp này, mọi thứ đều tốt.


-1

Bạn có thể giải quyết lỗi này bằng cách thêm một hàm tạo không đối số vào lớp cơ sở (như hình bên dưới).

Chúc mừng.

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

Điều đó làm cho nó dễ dàng xây dựng các đối tượng không hợp lệ (những đối tượng không có someString) set và do đó hoàn toàn đánh bại mục đích của như một hàm tạo.
Robert

-1

Tôi đã gặp lỗi này và đã sửa nó bằng cách loại bỏ một ngoại lệ được ném từ bên cạnh phương thức thành một khối try / catch

Ví dụ: FROM:

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

}

ĐẾN:

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

  }catch(SQLException)
  { 
  }
}

Câu trả lời này không liên quan gì đến lỗi trình biên dịch đối với một hàm tạo bị thiếu.
Robert
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.