2017-01-24 5 views
14

После прочтения Why can't overriding methods throw exceptions, Я понимаю, что если метод объявлен как бросает проверяемое исключение, наиважнейший метод в подклассе может объявить только выбросить это исключение или его подкласс:Вызова метода переопределения, что броски Проверены исключение

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 
} 

Итак, потому что SocketException IS-A IOException Я могу объявить метод переопределения как бросающий любой подкласс IOException.

В моей программе я хочу вызвать метод переопределения, объявленный как броски FileNotFoundException IS-A IOException. также обрабатываются с блоком примерки поймать

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{} 
} 

Но я получаю, что ошибка времени компиляции: Screenshot

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

Какова причина этого? Я немного смущен, потому что все, что класс Base также доступен для подклассов.

Также гораздо более запутанной является способность ловить Exception и Throwable В дополнение к IOException (Противоположность концепции Переопределения).

+3

У некоторых людей могут быть заблокированы изображения. Можете ли вы также скопировать вставьте ошибку компиляции в свой вопрос. – CKing

+2

@CKing добавлен прямо сейчас – Pauwelyn

ответ

10

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

Вы должны поймать IOException и не FilenotFoundException. Это связано с тем, что, хотя метод doStuff из подкласса будет вызываться во время выполнения, компилятор пока не знает об этом. Он знает только о методе doStuff в суперклассе, который заявляет, что он throws a IOException.

Чтобы обратиться к вашему редактированию: блок catch может выбрать точное исключение, которое ожидается в блоке try, или оно может выбрать захват суперкласса исключения. Обоснование этого не имеет ничего удаленного с переопределением метода.

2

Это потому, что вы используете объект статического типа Super. Компилятор не может знать, что во время выполнения p указывает на объект Sub, поэтому он хочет поймать исключения, вызванные методом, объявленным в классе Super

14

Ссылка на объект имеет тип Super, хотя вы знаете, что это a Sub объект во время выполнения. Поэтому компилятор проверяет определение метода Super и дает вам эту ошибку компиляции.

Это не будет отличаться от получать следующее сообщение об ошибке компилятора:

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

Важно помнить, что положение throws является частью определения метода.

+1

Но, java.lang.Object не имеет метода 'charAt'. Хотя' Super' и 'Sub' имеет – Pauwelyn

+2

Согласовано. Однако принцип точно такой же, компилятор только проверяет, что методы, которые вы вызываете, находятся в ссылочном типе («Объект» в моем примере «Супер» в вашем случае). – StuPointerException

2

Потому что он делает проверки по заявленному типу, в данном случае Super.

Неизвестно (или отмечено), что ваш p будет содержать только экземпляры Sub. Кроме того, было бы бессмысленно определять переменную суперкласса и использовать ее только и только для одного конкретного подкласса.

Таким образом, ваш Super p содержит экземпляр Super.class. Его метод doStuff() может выбросить все, что распространяется на IOException, скажем UnsupportedEncodingException, но вы пытаетесь поймать только для FileNotFoundException, так что Unsupported..., возможно, были выброшены и должны быть обработаны.

5

Компилятор не рассматривает тип объекта, но тип ссылки, которую вы используете, это Super.

Как Super.doStuff() throws IOException, это то, что вы должны поймать.

BTW Я настоятельно рекомендую использовать IDE, вы найдете его более продуктивным.

+0

Почему я могу использовать также 'Exception' и' Throwable' В дополнение к 'IOException'? Это отличие от переопределения, которое может объявить только о том, чтобы исключить это исключение или его подкласс – Pauwelyn

+0

@Pau переопределенный метод не может их выбросить, но вы можете их поймать –

3

Объявив р как супер

Super p = ... 

ваш компилятор знает p это своего рода Super. SuperdoStuff() выбрасывает IOException, но ваш код ловит только специальный случай IOException, FileNotFoundException. Если вы хотите рассказать своему компилятору, это определенно Sub, а не Super просто объявите p как Sub.

В данном случае это явно не объявлен как Sub но Super поэтому любой Super или его Чайлдс может произойти и бросить любую IOException, которые не могут быть FileNotFoundException или любой из его Чайлдс.

Смежные вопросы