Вызов метода переопределения, который выдает проверенное исключение
После чтения Почему нельзя переопределять методы для исключения исключений, я понимаю, что если метод объявлен как выбравший исключение Checked, метод переопределения в подклассе может только объявлять бросить это исключение или его подкласс:
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
.
В моей программе я хочу вызвать метод переопределения, объявленный как throws FileNotFoundException
IS-A IOException
. также обрабатывается блоком 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{}
}
Но я получаю эту ошибку времени компиляции:
![Снимок экрана]()
Sub.java:6: error: unreported exception IOException; must be caught or declared to be thrown
p.doStuff();
^
В чем причина этого? Я немного смущен, потому что все, что базовый класс также доступен для подклассов.
Также гораздо более запутанной является способность ловить Exception
и Throwable
В дополнение к IOException
(противоположность концепции Overriding).
Ответы
Ответ 1
В чем причина этого? Я немного смущен, потому что все, что базовый класс также доступен для подклассов.
Вам нужно поймать IOException
, а не FilenotFoundException
. Это связано с тем, что, хотя метод doStuff
из подкласса будет вызываться во время выполнения, компилятор пока не знает об этом. Он знает только о методе doStuff
в суперклассе, который объявляет, что он throws
a IOException
.
Чтобы обратиться к редактированию: блок catch
может выбрать точное исключение, ожидаемое в блоке try
, или он может выбрать захват суперкласса исключения. Обоснование этого не имеет ничего удаленного с переопределением метода.
Ответ 2
Ссылка на объект имеет тип Super
, хотя вы знаете его как объект Sub
во время выполнения. Поэтому компилятор проверяет определение метода Super
и дает вам эту ошибку компиляции.
Это не будет отличаться от получения следующей ошибки компилятора:
Object o = new String("Hello World");
o.charAt(2); //Obviously not allowed
Важно помнить, что предложение throws
является частью определения метода.
Ответ 3
Компилятор не рассматривает тип объекта, а тип ссылки, который вы используете, Super
.
Как Super.doStuff() throws IOException
, это то, что вы должны поймать.
Кстати, я настоятельно рекомендую использовать IDE, вы найдете его более продуктивным.
Ответ 4
Объявив p как Super
Super p = ...
ваш компилятор знает, что p
- это своего рода Super
. Super
doStuff()
выбрасывает IOException
, но ваш код ловит только специальный случай IOException
, FileNotFoundException
. Если вы хотите сообщить своему компилятору, это определенно Sub
, а не Super
просто объявить p
как Sub
.
В этом случае он явно не объявлен как Sub
, а как Super
, поэтому любой Super
или его дочерние элементы могут возникнуть и выкинуть любой IOException
, который может не быть FileNotFoundException
или любым из его дочерних элементов.
Ответ 5
Это потому, что вы используете объект статического типа Super.
Компилятор не может знать, что во время выполнения p указывает на объект Sub, поэтому он хочет поймать исключения, выданные методом, объявленным в классе Super
Ответ 6
Поскольку он выполняет проверки по объявленному типу, в этом случае Super
.
Неизвестно (или проверено), что ваш p
будет содержать только экземпляры Sub
. Кроме того, было бы бессмысленно определять переменную суперкласса и использовать ее только и только для одного конкретного подкласса.
Итак, ваш Super p
содержит экземпляр Super.class
. Его метод doStuff()
может выкинуть все, что расширяет IOException
, скажем UnsupportedEncodingException
, но вы пытаетесь поймать только для FileNotFoundException
, так что Unsupported...
может быть запущен и должен быть обработан.