2017-01-24 22 views
14

Sau khi đọc Why can't overriding methods throw exceptions, tôi hiểu rằng nếu phương pháp khai báo là ném một ngoại lệ Kiểm tra, phương pháp trọng trong một lớp con chỉ có thể tuyên bố để ném rằng ngoại lệ hoặc lớp con của nó:Gọi phương pháp trọng mà ném Kiểm tra ngoại lệ

class A { 
    public void foo() throws IOException {..} 
} 

class B extends A { 
    @Override 
    public void foo() throws SocketException {..} // allowed 

    @Override 
    public void foo() throws SQLException {..} // NOT allowed 
} 

Vì vậy, vì SocketException IS-A IOException Tôi có thể khai báo phương thức ghi đè như ném bất kỳ lớp con nào của IOException.

Trong chương trình của mình, tôi muốn gọi phương thức ghi đè được khai báo là ném FileNotFoundException IS-A IOException. cũng xử lý với một khối try-catch

import java.io.*; 
class Sub extends Super{ 
    public static void main (String [] args){ 
     Super p = new Sub(); 
     try { 
      p.doStuff(); 
     }catch(FileNotFoundException e){ 

     } 
    } 
    public void doStuff() throws FileNotFoundException{} 
} 

class Super{ 
    public void doStuff() throws IOException{} 
} 

Nhưng tôi nhận được rằng lỗi thời gian biên dịch: Screenshot

Sub.java:6: error: unreported exception IOException; must be caught or declared to be thrown 
        p.doStuff(); 
          ^

lý do cho điều đó là gì? Tôi hơi bối rối vì mọi thứ mà lớp Base cũng có sẵn cho các lớp con.

Cũng khó hiểu hơn nhiều là khả năng bắt ExceptionThrowable Ngoài IOException (Ngược lại với khái niệm ghi đè).

+3

Một số người có thể bị chặn hình ảnh. Bạn cũng có thể sao chép dán lỗi biên dịch vào câu hỏi của mình không. – CKing

+2

@CKing được thêm ngay bây giờ – Pauwelyn

Trả lời

10

What is the reason for that? I'm a little confused because everything that the Base class has also available to the subclasses.

Bạn cần phải nắm bắt IOException và không phải là FilenotFoundException. Điều này là do thực tế rằng trong khi phương thức doStuff từ lớp con sẽ được gọi khi chạy, trình biên dịch không biết về điều này. Nó chỉ biết về phương pháp doStuff trong lớp siêu mà tuyên bố rằng nó throws một IOException.

Để giải quyết chỉnh sửa của bạn: Khối catch có thể chọn để nắm bắt ngoại lệ chính xác được mong đợi trong khối try hoặc nó có thể chọn bắt siêu lớp ngoại lệ. Lý do đằng sau điều này đã không có gì từ xa để làm với phương pháp ghi đè.

2

Đó là vì bạn đang sử dụng đối tượng loại siêu tĩnh. Trình biên dịch không thể biết rằng tại thời gian chạy p trỏ đến một đối tượng phụ, vì vậy nó muốn nắm bắt các ngoại lệ được ném theo phương thức được khai báo trong lớp Super

14

Tham chiếu đối tượng của bạn là loại Super, mặc dù bạn biết một đối tượng Sub khi chạy. Do đó trình biên dịch đang kiểm tra định nghĩa phương thức của Super và cung cấp cho bạn lỗi biên dịch này.

Nó sẽ không có khác biệt so với nhận được lỗi biên dịch sau:

Object o = new String("Hello World"); 
o.charAt(2); //Obviously not allowed 

Điều quan trọng là phải nhớ rằng mệnh đề throws là một phần của định nghĩa phương pháp.

+1

Nhưng, java.lang.Object không có phương thức 'charAt' Trong khi cả hai' Super' và 'Sub' đều có – Pauwelyn

+2

Đồng ý. Tuy nhiên, hiệu trưởng chính xác như nhau, trình biên dịch chỉ kiểm tra xem các phương thức bạn đang gọi có thuộc kiểu tham chiếu ('Object' trong ví dụ của tôi,' Super' trong trường hợp của bạn) hay không. – StuPointerException

2

Vì nó làm cho séc bằng loại được khai báo, trong trường hợp này là Super.

Không rõ (hoặc được kiểm tra) rằng p của bạn sẽ chỉ chứa các trường hợp Sub. Ngoài ra, nó sẽ không có ý nghĩa để xác định một biến siêu lớp và chỉ sử dụng nó và chỉ cho một lớp con cụ thể.

Vì vậy, Super p của bạn chứa phiên bản Super.class. Phương thức của nó doStuff() có thể ném mọi thứ mở rộng IOException, cho phép nói UnsupportedEncodingException, nhưng bạn chỉ thử bắt giữ FileNotFoundException, để Unsupported... có thể đã bị ném và phải được xử lý.

5

Trình biên dịch không xem xét loại đối tượng, nhưng loại tham chiếu bạn đang sử dụng là Super.

Super.doStuff() throws IOException, đây là những gì bạn phải nắm bắt.

BTW Tôi khuyên bạn nên sử dụng IDE, bạn sẽ thấy nó hiệu quả hơn.

+0

Tại sao tôi có thể sử dụng 'Exception' và' Throwable' Ngoài 'IOException'? Đối diện với Ghi đè chỉ có thể khai báo để ném ngoại lệ đó hoặc lớp con của nó – Pauwelyn

+0

@Pau, phương pháp ghi đè không thể ném chúng nhưng bạn có thể bắt chúng –

3

Bằng cách khai báo p là Super

Super p = ... 

trình biên dịch của bạn chỉ biết p là một số loại Super. 's doStuff() ném một số IOException, nhưng mã của bạn chỉ bắt được một trường hợp đặc biệt là IOException, FileNotFoundException. Nếu bạn muốn thông báo cho Trình biên dịch của mình, điều này chắc chắn là Sub và không phải là Super chỉ cần khai báo pSub.

Trong trường hợp này đó là rõ ràng không khai báo là Sub nhưng như Super vì vậy bất kỳ Super hoặc Childs của nó có thể xảy ra và ném bất kỳ IOException mà có thể không phải là một FileNotFoundException hoặc bất kỳ của nó Childs.

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