Вызов метода переопределения, который выдает проверенное исключение

После чтения Почему нельзя переопределять методы для исключения исключений, я понимаю, что если метод объявлен как выбравший исключение 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... может быть запущен и должен быть обработан.