2015-08-10 17 views
15

Gần đây tôi đã chơi xung quanh với một số mã Java đơn giản sử dụng phương pháp main để nhanh chóng kiểm tra mã tôi đã viết. Tôi đã kết thúc trong một tình huống mà tôi đã hai lớp tương tự như:Sự khác biệt chữ ký khi ẩn phương pháp tĩnh trong một phân lớp

public class A { 
    public static void main(String[] args) { 
     // code here 
    } 
} 



public class B extends A { 
    public static void main(String[] args) throws IOException { 
     // code here 
    } 
} 

Tôi đã khá ngạc nhiên rằng mã ngừng biên soạn và Eclipse phàn nàn rằng Exception IOException is not compatible with throws clause in A.main(String[]). Vâng, cả hai phương pháp đều tĩnh và hàm main trong B chỉ là ẩn một từ A, vì vậy tôi nghĩ rằng hoàn toàn không có mối quan hệ nào giữa chúng. Trong phương pháp tĩnh, chúng tôi không có đa hình và cuộc gọi được ràng buộc với việc thực hiện phương pháp cụ thể trong quá trình biên dịch, do đó tôi không thể hiểu tại sao main trong B không thể ném ngoại lệ.

Tại sao các nhà thiết kế Java quyết định thực thi một ràng buộc như thế này và trong tình huống nào nó sẽ gây ra vấn đề nếu ràng buộc không được trình biên dịch thi hành?

Trả lời

5

Đối với những gì đáng giá, đây là phần liên quan của JLS thực thi quy tắc này.

Thứ nhất, §8.4.8.2. Hiding (by Class Methods) đưa ra một định nghĩa cho phương pháp ẩn mà áp dụng ở đây:

Nếu một lớp C tuyên bố hoặc được thừa hưởng một phương pháp staticm, sau đó m được cho là ẩn bất kỳ phương pháp m', nơi chữ ký của m là một phần phụ (§8.4.2) chữ ký của m', trong các lớp siêu lớp và siêu kết nối của C mà nếu không sẽ có thể truy cập được mã trong C.

Sau đó, §8.4.8.3. Requirements in Overriding and Hiding khẳng định rằng:

Một phương pháp đó sẽ ghi đè hoặc ẩn một phương pháp khác, bao gồm cả các phương pháp mà thực hiện abstract phương pháp quy định tại các giao diện, có thể không được công bố để ném nhiều kiểm tra ngoại lệ so với phương pháp ghi đè hoặc ẩn.

Chính xác hơn, giả sử rằng B là một lớp hoặc giao diện, và A là một lớp cha hoặc superinterface của B, và một phương pháp kê khai m2 trong ghi đè B hoặc ẩn một phương pháp kê khai m1 trong A. Sau đó:

  • Nếu m2 có điều khoản throws đề cập đến bất kỳ loại ngoại lệ đã chọn nào, thì m1 phải có điều khoản throws hoặc xảy ra lỗi biên dịch.

  • Đối với mỗi kiểm tra loại trừ được liệt kê trong throws khoản của m2, cùng một lớp ngoại lệ hoặc một trong những siêu kiểu của nó phải xảy ra trong tẩy xoá (§4.6) của throws khoản của m1; nếu không, một lỗi biên dịch sẽ xảy ra.

Nói cách khác, thông báo lỗi không phải là một sự giám sát trong các trình biên dịch, hoặc một sự hiểu sai của spec; JLS thực hiện nỗ lực cụ thể để đề cập đến các xung đột khoản throws xung đột lỗi khi ẩn phương thức (tức là, với phương pháp tĩnh). Có ngôn ngữ tương đương với điều này trong mọi phiên bản của JLS trở lại 1.0.

Tuy nhiên, tôi không thể trả lời dứt khoát câu hỏi của bạn về số lý do tại sao ràng buộc có trong trường hợp này. Tôi không thể quan niệm về bất kỳ tình huống nào trong đó ràng buộc là cần thiết, vì vấn đề thực thi phương thức tĩnh được gọi luôn luôn được giải quyết hoàn toàn tại thời gian biên dịch, không giống như các phương thức ví dụ.

Tôi đặt cược một khoản tiền nhỏ mà bất kỳ ai đặt ràng buộc đầu tiên trong langspec chỉ đơn giản là thận trọng, cho rằng an toàn hơn để ngăn chặn điều gì đó hơn là cho phép và sau đó phát hiện ra nó gây ra sự cố.Thiết kế ngôn ngữ Java là/không phải không có chia sẻ công bằng các tính năng thiếu sót (các trường hợp ngoại lệ đã kiểm tra là một trong số chúng), và điều này có thể là một cách khác, nhưng đây chỉ là một phỏng đoán.

-3

Từ khóa 'mở rộng' có nghĩa là bạn đang kế thừa các phương thức từ lớp A khi bạn khai báo lớp B. Vì lớp A là lớp cha của lớp B, khai báo của phương thức chính vẫn nằm trong lớp A mặc dù thực tế bạn đang xác định lại nó trong Class B.

Khi bạn đang xử lý các phương thức tĩnh, phương thức lớp cha không bị ghi đè bởi lớp con, nó chỉ đơn giản là ẩn.

http://docs.oracle.com/javase/tutorial/java/IandI/override.html

có thể cung cấp chi tiết hơn, nhưng đây là một đoạn trích:

Sự khác biệt giữa giấu một phương pháp tĩnh và trọng một phương pháp dụ có ý nghĩa quan trọng:

Các phiên bản của ghi đè phương thức thể hiện được gọi là một trong lớp con. Phiên bản của phương thức tĩnh ẩn được gọi là được gọi phụ thuộc vào việc nó được gọi từ lớp cha hay lớp con .


câu trả lời ban

hạn chế này được buộc bởi trình biên dịch để giúp đơn giản hóa kế thừa trong hệ thống phân cấp phức tạp hơn.

Lấy phương thức toString() chẳng hạn. Nó được thừa kế bởi mọi đối tượng trong Java, hãy tưởng tượng nếu bạn có thể ghi đè khai báo của phương thức này để cho phép các lớp con ném các ngoại lệ khác nhau. Đó là một công thức cho thiên tai về xử lý tất cả những ngoại lệ tiềm ẩn mới.

TLDR- Trình biên dịch buộc bạn phải tuân theo định nghĩa hàm lớp cha để các lập trình viên khác có thể ngủ vào ban đêm.

+5

Chìa khóa ở đây là chính là phương pháp 'tĩnh', có vẻ như bạn đã bỏ qua phần đó của câu hỏi hoàn toàn. Tính đa hình không áp dụng cho các phương thức 'tĩnh'. EDIT: Tôi nhớ nghe điều này thay đổi trong Java 8, mà cho tiết lộ đầy đủ tôi đã không được sử dụng. –

1

Vấn đề là chúng ta đang nói về các phương pháp tĩnh, mà thực sự không được cho là bị ảnh hưởng bởi đa hình. Tuy nhiên, có vẻ như với tôi rằng các phương pháp tĩnh thuộc về một đối tượng Class, giống như bất kỳ đối tượng nào khác phải tuân theo tính đa hình, đúng không?

+0

Đa hình chỉ áp dụng cho phương pháp không riêng tư, cuối cùng hoặc tĩnh. – Pshemo

+0

Nhân tiện, điều này có vẻ là một bản sao của [câu hỏi này] (http://stackoverflow.com/questions/2223386/why-doesnt-java-allow-overriding-of-static-methods) –

+1

Nó không phải là một bản sao vì tôi không tự hỏi tại sao các phương thức tĩnh là không thể - tôi biết rằng các phương thức tĩnh hoàn toàn khác với các phương thức mẫu và tính đa hình không hoạt động ở đó, đó là điểm thảo luận chính trong chuỗi bạn liên kết tới. –

2

Tôi chưa bao giờ nhận ra về thực tế này, nhưng sau khi phân tích chính xác, tôi không thấy lý do tại sao trình biên dịch phải thực thi một ràng buộc như vậy. Rõ ràng là không, sẽ không có sự không thống nhất có thể khi kết hợp phương thức main, vì việc liên kết một phương thức tĩnh cũng là tĩnh. Không được phép ghi đè trong trường hợp này.

+1

Bài đăng của bạn trông giống như xác nhận vấn đề được mô tả bởi OP thay vì trả lời (trừ khi tôi bỏ lỡ điều gì đó - đó là nơi tôi sống). – Pshemo

+3

Tác giả hỏi "Trong tình huống nào nó sẽ gây ra vấn đề" và tôi đã trả lời "Tôi không thể nhìn thấy bất kỳ ai". Đó là câu trả lời. –

+2

Tôi hiểu ý của bạn, nhưng điều đó dường như không giải thích được nhiều, nó chỉ đơn giản khẳng định những nghi ngờ của OP rằng không có vấn đề gì. Vì vậy, đối với tôi nó trông giống như "Tôi đồng ý" đó là giống như bình luận hơn câu trả lời. – Pshemo

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