2009-07-29 33 views
84

Tôi có một số mã Java đơn giản mà trông tương tự như sau trong cấu trúc của nó:lỗi Java: Implicit siêu constructor là undefined cho constructor mặc định

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ó một vài lớp con của BaseClass, mỗi thực hiện getName() phương pháp theo cách riêng của mình (template method pattern).

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

Khi tôi loại bỏ các nhà xây dựng từ các lớp con, tôi có được điều này lỗi thời gian biên dịch:

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

phải là những gì tôi đang cố gắng để làm tốt?

+1

Vui lòng để nguyên 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 có thể tự động tạo ra nó, vì vậy bạn chỉ cần nhấn phím tắt. –

+3

Đọc lại câu hỏi của riêng tôi một năm sau đó và nó xảy ra với tôi rằng tôi có thể loại bỏ các nhà xây dựng (bao gồm trong lớp cơ sở) như matt b gợi ý, và sau đó sử dụng một phương pháp nhà máy tĩnh để xây dựng trường hợp. – Joel

Trả lời

138

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

public ACSubClass() { 
    super(); 
} 

Tuy nhiên kể từ BaseClass của bạn tuyên bố một constructor (và do đó không có constructor mặc định, no-arg mà trình biên dịch sẽ cung cấp) đ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 có đối số trong BaseClass.

Đây có thể là một chút phản trực giác bởi vì bạn có thể nghĩ rằng một phân lớp 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 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 là no-arg) hoặc có một hàm tạo no-arg được khai báo (hoặc là chính nó hoặc cùng với các hàm tạo khác). Nhưng thường thì cách tiếp cận này không thể áp dụng được - bởi vì bạn cần bất kỳ đối số nào được truyền vào hàm tạo để xây dựng một cá thể hợp lệ của lớp.

+16

"Đây có thể là một chút phản trực giác bởi vì bạn có thể nghĩ rằng một phân lớp tự động có bất kỳ hàm tạo nào mà lớp cơ sở có." +1 –

+1

Vì lợi ích của hậu thế, tôi sẽ đề xuất giải pháp của tôi cho người đọc trong tương lai: tạo một hàm tạo no-arg trong 'BaseClass' nhưng làm cho nó đơn giản ném một' UnsupportedOperationException' hoặc cái gì đó. Nó không phải là giải pháp tốt nhất (nó sai cho thấy rằng lớp có thể hỗ trợ một constructor no-arg), nhưng đó là tốt nhất tôi có thể nghĩ đến. – JMTyler

7

Có thể nhưng không theo cách bạn có.

Bạn phải thêm một hàm tạo không-arg vào lớp cơ sở và đó là nó!

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ỳ) nào vào một trình biên dịch, hãy thêm mặc định không có contructor 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 bạn nhận được thông báo lỗi đó.

Đó là về câu hỏi đó.

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) để xác định một giá trị khác nhau (dữ liệu) làm cho không có ý nghĩa ?? !!! 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 parametrized 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

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 này:

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

If I were to change the method signature of the BaseClass constructor, I would have to change all the subclasses.

Vâng đó là lý do thừa kế là tạo tác tạo ra khớp nối HIGH, đó là unde mong muốn trong các hệ thống OO. Cần tránh và có thể thay thế bằng chế phẩm.

Hãy suy nghĩ xem bạn có thực sự cần chúng làm lớp con hay không. Đó là lý do tại sao bạn thấy rất thường xuyên giao diện sử dụng insted:

public interface NameAware { 
    public String getName(); 
} 



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

Đây B và C có thể thừa hưởng từ A mà sẽ tạo ra một sự kết hợp rất cao trong số đó, bằng cách sử dụng giao diện các khớp nối giảm, nếu A quyết định nó sẽ không còn là "NameAware" 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, thao tác này sẽ không hoạt động.

+2

Có, ngoại trừ bạn không còn có thể đảm bảo rằng các phiên bản của bạn được khởi tạo đúng cách (ví dụ: có tên trong trường hợp cụ thể này) – ChssPly76

+0

@ ChssPly76: Có, nhưng đó có thể là do thừa kế đang được sử dụng một cách kém. Tôi mở rộng câu trả lời của tôi để trang trải nó. – OscarRyz

0

BaseClass của bạn cần một someString để cung cấp một.
Hãy thử điều này:

abstract public class BaseClass { 
    String someString; 
    public BaseClass(String someString) { 
     this.someString = someString; 
    } 
    abstract public String getName(); 
} 

public class ACSubClass extends BaseClass { 
    public ASubClass() { 
     super("someString"); // or a meaningfull value, same as getName()? 
    } 
    public String getName() { 
     return "name value for ASubClass"; 
    } 
} 

hoặc

abstract public class BaseClass { 
    String someString; 
    protected BaseClass() { // for subclasses 
     this.someString = null; // or a meaningfull value 
    } 
    public BaseClass(String someString) { 
     this.someString = someString; 
    } 
    abstract public String getName(); 
} 

public class ACSubClass extends BaseClass { 
    public String getName() { 
     return "name value for ASubClass"; 
    } 
} 
41

Đối với những người của Google cho lỗi này và đến ở đây: có thể có một lý do khác để tiếp nhận nó. Eclipse đưa ra lỗi này khi bạn có 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 có 1.7 thiết lập đúng thì bạn sẽ gặp phải lỗi này. Sau đó, bạn có thể truy cập Project - Preference - Java - Compilerswitch to 1.6 or earlier; hoặc truy cập Window - Preferences - Java - Installed JREs và thêm/sửa cài đặt JRE 1.7 của bạn.

+1

Chỉ gặp lỗi này vì không có lý do rõ ràng nào trong Eclipse. Sau đó, tôi làm sạch không gian làm việc (menu Project -> Clean ...) và nó đã biến mất. – erickrf

-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 có đối số vào lớp cơ sở (như được hiển thị 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"; 
    } 
} 
+0

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

0

Một cách khác là gọi super() với đối số bắt buộc làm tuyên bố đầ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 hàm tạo siêu lớp làm tuyên bố đầu tiên trong hàm tạo lớp con.

-1

Tôi có lỗi này và cố định nó bằng cách loại bỏ một ngoại lệ ném từ bên cạnh phương pháp để một khối try/catch

Ví dụ: TỪ:

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

} 

TO:

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

    }catch(SQLException) 
    { 
    } 
} 
+0

Câu trả lời này không liên quan gì đến lỗi trình biên dịch cho một hàm tạo bị thiếu. – Robert

1

lỗi này xảy ra do JRE không được thiết lập nên hãy làm theo các bước sau:


1. clic phải k project -> Properties -> Java Build Path -> Nhấp vào tab Libraries
2. nhấp Thêm Thư viện
3. Chọn Thư viện Hệ thống JRE -> Nhấp vào Tiếp theo
4. Chọn jre mặc định của Workspace hoặc jre được cài đặt thay thế
5. nhấp vào kết thúc

+0

Gosh, OP thậm chí không nói IDE nào (nếu có) anh ta đang sử dụng ... – Robert

0

Xin lỗi vì đã phá hoại nhưng phải đối mặt với vấn đề này ngay 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ể - bạn không gọi super ở dòng đầu tiên của phương pháp. Thứ hai, thứ ba và các dòng khác cháy lỗi này. Cuộc gọi của siêu nên được gọi đầu tiên trong phương pháp của bạn. Trong trường hợp này mọi thứ đều ổn.

Các vấn đề liên quan