2015-04-20 17 views
6

Giả sử chúng ta có hai lớp:Mở rộng ngoại trừ phương pháp ghi đè trong Java

Class A:

import java.io.IOException; 

public class A { 
    public void test() throws IOException{ 
     System.out.println("test in A"); 
    } 
} 

Class B:

import java.io.IOException; 

    public class B extends A { 
     @Override 
     public void test() throws Exception{ 
      System.out.println("test in B"); 
     } 
} 

này đưa ra một lỗi biên dịch, và tôi muốn để biết lý do cho nó. Tôi có thể tự mình nhận được câu trả lời, nhưng điều này không hoàn toàn khoa học, nhưng một phần logic.

Tôi đã viết a blog post in Azerbaijani. Khi tôi viết blog, tôi đã bị kẹt trong quá trình tải.

Xin hãy cẩn thận trong dấu ngoặc kép:

Tôi nghĩ rằng khi trình biên dịch lần đọc lớp B, nó tải các tiêu đề phương pháp A và tiêu đề phương pháp B. Và khi bạn gọi thử nghiệm của A, JVM kêu gọi sự thử thách của A, nhưng khi cơ thể gọi là thử nghiệm của B, và tại thời điểm đó chúng tôi sẽ có phương pháp này:

public void test() throws IOException{ // <-- Header of A 
    System.out.println("test in B"); // <-- Body of B 
    // Here I can throw wide Exception from IOException 
    // because here is the body of the test in B. The test 
    // method in B can throw Exception so the compiler 
    // doesn't approve of this version of the code. 
} 

là quá trình này thực sự xảy ra như những gì tôi đã viết ở trên?

Tải vấn đề tiêu đề Tôi đã bị kẹt chính xác ở đây. Quá trình liên kết hoạt động như thế nào? Tôi không thể tìm ra nền tảng của

A a = new B(); // When the compiler converts this line into bytecode 
//    does it loads of method headers of A and method 
//    body's of B 
a.test() 

gọi kiểm tra của lớp B. Tôi biết một cách hợp lý, nhưng tôi không thể tìm ra ở cấp độ trình biên dịch, quá trình liên kết.

Trả lời

9

Imaigine bạn có đoạn mã sau:

A a = new B(); 
try { 
    a.test(); 
} catch (IOExceoption e) { 
    //do some specific handle for IOExceoption 
} 

Bây giờ imaigine những gì sẽ xảy ra nếu b.test() ném một Exception đó là KHÔNG IOException? không ai sẽ xử lý nó và phá vỡ cơ chế checked exceptions của java.


Một cách khác xung quanh tuy nhiên, là hoàn toàn tốt đẹp:

public class A { 
    public void test() throws Exception { 
     System.out.println("test in A"); 
    } 
} 
    public class B extends A { 
     @Override 
     public void test() throws IOException{ 
      System.out.println("test in B"); 
     } 
} 

A a = new B(); 
try { 
    a.test(); 
} catch (Exception e) { 
    //handle 
} 

Bây giờ, lưu ý rằng bắt xử lý một vị tướng Exception, bao gồm cụ thể IOException, và mã sẽ biên dịch một cách hoàn hảo.

+0

cảm ơn trả lời.hãy đọc câu hỏi lần nữa tôi đã cập nhật – Sarkhan

+0

@ Serkhan Khi nó thấy B.test() ghi đè A.test(), nó cũng kiểm tra sự kết hợp của kiểu trả về và ngoại lệ. Cả hai chỉ có thể được thu hẹp và không mở rộng, để ngăn chặn tình hình tôi đã thảo luận trong câu trả lời của tôi. – amit

+0

bạn có thể giải thích cho tôi quá trình liên kết không. Tôi không thể tìm ra nền tảng của A a = new B(); a.test() gọi kiểm tra của lớp B.i biết logically.but không thể tìm ra như trình biên dịch cấp như liên kết process.A a = new B(); // khi trình biên dịch chuyển đổi dòng này thành bytecode // nó có nạp các tiêu đề phương thức của A và phương thức của B hoặc tải của tất cả các tiêu đề phương thức và phần thân phương thức.i đang yêu cầu điều này để hiểu cách phương thức thử nghiệm của A liên kết với phương pháp kiểm tra B – Sarkhan

3

Phương thức được ghi đè có thể ném bất kỳ thứ gì , đây là trường hợp IOException của bạn. Hoặc nói chung hơn, nó có thể ném bất kỳ ngoại lệ nào là ParentException. Vì vậy, bạn có thể ném FileNotFoundException vì nó cũng là một IOException.

Tại sao?

Không tuân thủ quy tắc này vi phạm hợp đồng chính giữa cha mẹ và con trong kế thừa.

Một nơi nào đó khác trong mã của bạn một cách an toàn bạn có thể giả định rằng ngoại lệ ném từ các cuộc gọi đến test() sẽ luôn IOException không phân biệt nào thực hiện của A ném nó. Nếu bạn được phép ném InterruptedException trong trường hợp của bạn, người gọi sẽ phải loại trừ ngoại lệ nào?

Trình biên dịch không tải bất kỳ thứ gì. Nó chỉ đánh dấu phương thức như gọi ảo, có nghĩa là phương thức này được overriden và được gọi là run-time dựa trên kiểu đối tượng

+0

cảm ơn bạn đã trả lời. Vui lòng đọc câu hỏi một lần nữa tôi cập nhật – Sarkhan

+0

@Serkhan - The Compiler nhận ra rằng lớp 'A' là cha của' B'. Vì vậy, nó cũng phát hiện ra rằng 'test()' được ghi đè. Vì vậy, như là một * quy tắc * nó kiểm tra nếu ngoại lệ được ném bởi 'B.test()' là 'ParentException' hoặc' ParentExceptionChild' hợp lệ. Khác, nó không hợp lệ theo ngữ nghĩa ngôn ngữ – TheLostMind

+0

A a = new B(); // khi trình biên dịch chuyển đổi dòng này thành bytecode // nó tải các tiêu đề phương thức của A và phương thức của B hoặc tải của tất cả các tiêu đề phương thức và phần thân phương thức.i đang yêu cầu điều này để hiểu cách phương thức thử nghiệm của A liên kết với phương pháp thử nghiệm của B – Sarkhan

2

Từ một góc khác, về cơ bản bạn không ghi đè phương thức hiện có trong siêu loại.

Ngoại lệ được ném là một phần của chữ ký của phương thức. Khi bạn khai báo phương pháp thử trong lớp B với chú thích ghi đè, bạn đang thực sự cố gắng ghi đè (hoặc thực hiện) phương thức không tồn tại trong phụ huynh A.

+0

cảm ơn cho reply.please đọc lại câu hỏi tôi đã cập nhật – Sarkhan

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