Это действительно очень сложно.Чтобы понять это, вы должны вернуться к концепции наследования в объектно-ориентированной парадигме:
- Если я хочу создать ArrayList, я мог бы сделать это двумя различными способами:
- Первый - игнорирование всей концепции наследования, жесткое кодирование ArrayList и установка его типа как самого ArrayList:
ArrayList<String> list = new ArrayList<String>();
- Второй - следование концепции наследования, и мы пытаемся создать экземпляр на более высоком уровне.класс / интерфейс:
List<String> list = new ArrayList<String>();
Этот второй подход лучше по многим причинам, которые я не буду упоминать, поскольку он не входит в объем ответа, но поскольку ArrayList наследуется отList, мы можем создать новый ArrayList как объект List, но сделать что-то подобное невозможно, потому что List
не расширяется или не наследуется от ArrayList
:
ArrayList<String> list = new List<String>();
Та же идея применима кПойманные исключения Java.Следуя вашему примеру, если у меня есть:
class A extends Exception {}
class B extends A {}
class C extends B {}
Когда я пытаюсь поймать исключение, я сначала хочу попробовать класс более низкого уровня (C
) (то есть более конкретный), потому что у меня естьбольшая уверенность в том, что это значит:
try {
// something here that throws C
} catch (C exc) {
// Great! Its C! I know exactly what should I do!
} catch (B exc) {
// Not that great, it might not be that hard to figure out what caused this
} catch (A exc) {
// I still have some idea of what might have thrown this exception
} catch (Exception e) {
// Oh boy, its not an exception that I mapped before... It might be harder than I thought... :(
}
Но мы должны следовать той же мысли, что и ArrayList
, не имея возможности получить List
объект в исключениях:
- a Исключение C может быть перехвачено
catch (C exc)
, catch (B exc)
, catch (A exc)
и catch (Exception e)
- a Исключение B может быть перехвачено
catch (B exc)
, catch (A exc)
и catch (Exception e)
- a Исключение может быть поймано
catch (A exc)
и catch (Exception e)
- и т. Д. ...
Так как A относится к «более высокому уровню», чемB, это не может быть поймано catch (B exc)
.Вот почему он не компилируется в вашем примере:
void f() {
try {
throw new A();
} catch (B b) { // will not compile
}
}
Внутри спецификации на странице , на которую вы ссылались , прямо перед 11.3 есть фрагмент кода, который иллюстрирует то, что вы спрашивали, потому что какЯ уже объяснил, вы все правильно поняли:
Ошибка времени компиляции, если предложение catch может перехватить проверенный класс исключений E1, и это не тот случай, когда блок try, соответствующий предложению catchможет генерировать проверенный класс исключений, который является подклассом или суперклассом E1, если только E1 не является Exception или суперклассом Exception.
Это означает, что вы не можете перехватить подкласс предыдущего блока catch, и javaкомпиляторы увидят это как ошибку.Например, если вы попытаетесь сделать это
try {
throw new C();
} catch (A exc) {
// do something here, because the exception will be caught
} catch (B exc) {
// since the exception has been caught before and B is subclass of A,
// this causes the compilation error that JLS was talking about:
// you cannot catch a subclass of a class previously caught.
}