2011-10-25 38 views
6

Tôi có các lớp ví dụ sau trong Java:Không thể gọi trực tiếp supertype constructor - tại sao không?

public class A { } 

public class Super { 
    protected Super() { } 
    public Super(A a) { } 
} 

public class Sub extends Super { } 

public class Consumer { 
    public Consumer() { 
     Sub sub = new Sub(new A()); //compiler error 
    } 
} 

Trình biên dịch báo lỗi nói rằng các đối số không thể được áp dụng cho các nhà xây dựng mặc định trong Sub, mà là hoàn toàn dễ hiểu.

Điều tôi tò mò là lý do đằng sau quyết định này. Java tạo ra hàm tạo rỗng mặc định trong Sub; tại sao nó không thể gọi nó đằng sau hậu trường trong trường hợp này? Đây có phải là trường hợp chủ yếu của việc nắm tay sane hay có lý do kỹ thuật không?

EDIT

Tôi biết rằng đây là một giới hạn ngôn ngữ. Tôi tò mò về lý do tại sao đó là giới hạn ngôn ngữ.

EDIT 2

Dường như, như thường là trường hợp, tôi đã quá gần với mã tôi đã thực sự làm việc để xem hình ảnh lớn. Tôi đã đăng một ví dụ phản đối trong các câu trả lời dưới đây cho thấy lý do tại sao đây là Bad Thing®.

+0

Tất cả những gì tôi có thể tìm thấy trong thông số kỹ thuật là không thể thực hiện được. Không có lời giải thích nào về lý do tại sao http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.2 –

+1

Dưới đây là Jon Skeet's take on it http://stackoverflow.com/questions/1644317/java -constructor-inheritance/1644410 # 1644410 –

+1

Tôi đang bối rối về chỉnh sửa của bạn. Bạn đang tự hỏi tại sao, khi bạn gọi một hàm tạo với một đối số, một hàm tạo mặc định không có đối số không thể được gọi trong vị trí của nó? Rõ ràng các lập trình viên đã không cố gắng gọi một nhà xây dựng mà hoàn toàn sẽ bỏ qua tham số của mình, nếu không anh ta sẽ không có specifed tham số! –

Trả lời

2

Tôi nghĩ rằng đó là vấn đề về khả năng đọc và không giả định ý định. Bạn nói

Java tạo hàm tạo mặc định trống; tại sao nó không thể gọi nó đằng sau hậu trường trong trường hợp này?

Tuy nhiên, với tôi, nó sẽ có ý nghĩa nhiều hơn nữa cho Java để ngầm gọi constructor Super(A) "đằng sau hậu trường" hơn để gọi constructor Super(), bất chấp A.

Và ở đó bạn có nó. Chúng tôi đã có hai giả định khác nhau về những gì nên (hoặc có thể) xảy ra trong trường hợp này.

Một trong những nguyên tắc cốt lõi của ngôn ngữ Java là tính minh bạch. Càng nhiều càng tốt, lập trình viên có thể thấy bằng cách nhìn vào mã những gì sẽ xảy ra, đôi khi với chi phí tiện lợi hoặc ma thuật ở cấp độ cú pháp. Một nguyên lý song song với điều đó không nhằm mục đích giả định: trong trường hợp ý định của lập trình viên có vẻ mơ hồ, ngôn ngữ Java đôi khi sẽ ưu tiên biên dịch lỗi hơn là tự động chọn mặc định thông qua thuật toán lựa chọn (tùy ý hoặc khác).

+0

Những điểm tốt, nhưng dường như bạn đã hiểu lầm tuyên bố của tôi. Tôi sẽ cập nhật nó để làm cho nó rõ ràng hơn. Nó có thể không thay đổi đối số của bạn ... – arootbeer

2
public class Sub extends Super { } 

không có hàm tạo Sub (A a), nó chỉ có hàm tạo mặc định Sub().

Các nhà xây dựng không được kế thừa.

+0

Constructors được thừa hưởng đó là lý do tại sao nó không hoạt động. – mikek3332002

+0

@ mikek3332002: Tôi nghĩ chúng ta chỉ có thể gọi hàm tạo siêu lớp từ lớp con nhưng không được kế thừa. –

0

Bạn đã bỏ qua hàm khởi tạo công khai mặc định, vì vậy không có gì để gọi.

Vì vậy, các lớp Sub tương đương với

public class Sub extends Super 
{ 
    protected Sub(){} 
    public Sub(A a) { } 
} 

Nó sẽ vì nó

  • hành vi Sane - Hoạt động theo quy định của các lập trình viên, và nó cũng theo khái niệm về thừa kế trong các ngôn ngữ OOP
  • Theo di sản C++
2

Lớp cơ sở cần t o gọi các hàm tạo siêu để đảm bảo một đối tượng được khởi tạo đúng cách. Ví dụ xem xét:

class Super { 
    final String field1; 

    public Super(String field1) { 
     this.field1 = field1; 
    } 
    ... 
} 


class Base extends Super { 
    final String field2; 

    public Base(String field2) { 
     this.field2 = field2; 
    } 
    ... 
} 

Liệu constructor Base 's ghi đè lên các nhà xây dựng Super? Nếu vậy, thì trường1 không còn được đảm bảo để được khởi tạo, làm cho các phương thức kế thừa hoạt động bất ngờ.

Thời điểm bạn thêm một hàm tạo không mặc định vào lớp con, khi đó các hàm tạo kế thừa sẽ ngừng hoạt động. Tôi nghĩ rằng nó sẽ là một tính năng khó hiểu và hiếm khi được thêm vào ngôn ngữ, mặc dù về mặt kỹ thuật tôi không thể thấy lý do tại sao nó sẽ không thể.

+0

Vấn đề với ví dụ truy cập này là nó không liên quan đến các nhà xây dựng mặc định. Bạn đúng là mã này có vấn đề; nó thậm chí sẽ không biên dịch. Tuy nhiên, câu hỏi của tôi là cụ thể xung quanh các nhà xây dựng mặc định. – arootbeer

+0

Ví dụ của bạn hoạt động vì Sub không có các hàm tạo, và nó sẽ là một tính năng khó hiểu nếu các hàm tạo được thừa kế chỉ trong các trường hợp đó. –

+0

Ví dụ của tôi là vấn đề chỉ vì 'Sub' không có hàm tạo. Tôi sẽ đồng ý với bạn rằng nó sẽ gây nhầm lẫn, nhưng câu hỏi này là cố gắng tìm ra chính xác lý do tại sao nó sẽ gây nhầm lẫn. – arootbeer

0

Tôi đang coi đây là lý do kỹ thuật cho hành vi này; Tôi đồng ý với một số câu trả lời khác rằng điều này có thể gây nhầm lẫn về mặt ngữ nghĩa.

Hãy xem xét ví dụ sau:

public class A { } 

public abstract class Super { 
    protected Super() { 
     // perform time consuming, destructive, or 
     // otherwise one-time operations 
    } 

    public Super(A a) { 
     this(); 
     // perform A-related construction operations 
    } 
} 

public class Sub extends Super { } 

public class Consumer { 
    public Consumer() { 
     Sub sub = new Sub(new A()); 
    } 
} 

Khi Sub được xây dựng, trong trường hợp này các nhà xây dựng mặc định trên Sub sẽ được gọi, mà sẽ liên kết đến cái constructor mặc định trên Super (vì đó là sự kỳ diệu của ngôn ngữ định nghĩa). Sau đó, cuộc gọi đến Super(A) sẽ gọi logic được thiết kế để chạy một lần, lúc xây dựng. Điều này rõ ràng không phải là những gì các nhà phát triển dự định.

Ngay cả khi không có cuộc gọi this() trong hàm tạo Super(A), ý định của nhà phát triển không thể xác định được; các nhà thầu có thể loại trừ lẫn nhau vì một số lý do.

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