Я просматривал книгу SCJP 6, написанную Кэте Сьерра, и наткнулся на эти объяснения создания исключений в переопределенном методе. Я совершенно не понял. Кто-нибудь может мне это объяснить?
Переопределяющий метод НЕ должен генерировать проверенные исключения, которые являются новыми или более широкими, чем те, которые были объявлены переопределенным методом. Например, метод, который объявляет FileNotFoundException, не может быть переопределен методом, который объявляет SQLException, Exception или любое другое исключение, не относящееся к времени выполнения, если оно не является подклассом FileNotFoundException.
Ответы:
Это означает, что если метод объявляет выброс данного исключения, метод переопределения в подклассе может только объявить выброс этого исключения или его подкласса. Например:
SocketException extends IOException
, ноSQLException
не делает.Это из-за полиморфизма:
Если
B
бы вы решили выброситьSQLException
, то компилятор не смог бы заставить вас его поймать, потому что вы ссылаетесь на экземплярB
по его суперклассу -A
. С другой стороны, любой подклассIOException
будет обрабатываться с помощью предложений (catch или throws), которые обрабатываютIOException
Правило, которое вам нужно, чтобы иметь возможность ссылаться на объекты по их суперклассу, - это принцип подстановки Лискова.
Поскольку непроверенные исключения могут быть выброшены где угодно, они не подпадают под это правило. Вы можете добавить непроверенное исключение в предложение throws как форму документации, если хотите, но компилятор ничего не применяет к этому.
источник
@Override public void foo() {...}
это законно.Метод переопределения МОЖЕТ вызвать любое непроверенное исключение (во время выполнения), независимо от того, объявляет ли переопределенный метод исключение.
Пример:
источник
На мой взгляд, это ошибка в синтаксисе Java. Полиморфизм не должен ограничивать использование обработки исключений. Фактически, другие компьютерные языки этого не делают (C #).
Более того, метод переопределяется в более специализированном подклассе, что делает его более сложным и, по этой причине, с большей вероятностью генерировать новые исключения.
источник
Я даю здесь ответ на старый вопрос, так как никакие ответы не говорят о том, что метод переопределения ничего не может выбросить, вот что может вызвать метод переопределения:
1) выбросить то же исключение
2) throw подкласс выброшенного исключения переопределенного метода
3) ничего не бросать.
4) Наличие исключений RuntimeExceptions в бросках не требуется.
В бросках могут быть исключения RuntimeExceptions или нет, компилятор не будет на это жаловаться. RuntimeExceptions - это не проверенные исключения. Только отмеченные исключения должны появляться в бросках, если они не обнаружены.
источник
Чтобы проиллюстрировать это, рассмотрим:
Предположим, вы затем напишете:
Это приведет к ошибке компиляции, потому что r.close () выдает исключение IOException, которое шире, чем FileNotFoundException.
Чтобы исправить это, напишите:
Вы получите другую ошибку компиляции, потому что вы реализуете операцию perform (...), но генерируете исключение, не включенное в определение метода интерфейса.
Почему это важно? Ну, у потребителя интерфейса могут быть:
Если было разрешено генерировать исключение IOException, код клиента больше не является правильным.
Обратите внимание, что вы можете избежать такого рода проблем, если используете непроверенные исключения. (Я не предлагаю вам делать или не делать этого, это философский вопрос)
источник
Возьмем вопрос для интервью. Есть метод, который выдает исключение NullPointerException в суперклассе. Можем ли мы переопределить его с помощью метода, который генерирует исключение RuntimeException?
Чтобы ответить на этот вопрос, дайте нам знать, что такое исключение Unchecked и Checked.
Проверенные исключения должны быть явно перехвачены или распространены, как описано в разделе Базовая обработка исключений try-catch-finally. Для неотмеченных исключений это требование отсутствует. Их не нужно ловить или объявлять брошенными.
Проверенные исключения в Java расширяют класс java.lang.Exception. Непроверенные исключения расширяют java.lang.RuntimeException.
открытый класс NullPointerException расширяет RuntimeException
Непроверенные исключения расширяют java.lang.RuntimeException. Вот почему исключение NullPointerException является исключением без проверки.
Возьмем пример: Пример 1:
Программа успешно скомпилируется. Пример 2:
Программа также успешно скомпилируется. Поэтому очевидно, что в случае исключений Unchecked ничего не происходит. Теперь давайте посмотрим, что происходит в случае отмеченных исключений. Пример 3: Когда базовый класс и дочерний класс генерируют проверенное исключение
Программа успешно скомпилируется. Пример 4: Когда метод дочернего класса выдает исключение с проверкой границ по сравнению с тем же методом базового класса.
Программа не скомпилируется. Итак, мы должны быть осторожны, когда используем проверенные исключения.
источник
скажем, у вас есть суперкласс A с методом M1 throwin E1 и класс B, полученный из A с методом M2, переопределяющим M1. M2 не может бросить что-либо ИНОЕ или МЕНЬШЕ СПЕЦИАЛИЗИРОВАННОГО, чем E1.
Из-за полиморфизма клиент, использующий класс A, должен иметь возможность обращаться с B как с A. Inharitance ===> Is-a (B is-a A). Что, если этот код, имеющий дело с классом A, обрабатывал исключение E1, поскольку M1 объявляет, что он выбрасывает это проверенное исключение, но затем возник другой тип исключения? Если бы M1 выбрасывал IOException, M2 вполне мог бы выбросить FileNotFoundException, поскольку это - IOException. Клиенты A могут справиться с этим без проблем. Если бы выброшенное исключение было шире, клиенты A не имели бы возможности узнать об этом и, следовательно, не имели бы возможности его поймать.
источник
Ну, java.lang.Exception расширяет java.lang.Throwable. java.io.FileNotFoundException расширяет java.lang.Exception. Поэтому, если метод генерирует исключение java.io.FileNotFoundException, тогда в методе переопределения вы не можете выбросить что-либо выше по иерархии, чем FileNotFoundException, например, вы не можете выбросить java.lang.Exception. Однако вы можете создать подкласс FileNotFoundException. Однако вам придется обрабатывать исключение FileNotFoundException в методе переопределения. Придумайте код и попробуйте!
Правила существуют, поэтому вы не потеряете исходное объявление throw из-за расширения специфичности, поскольку полиморфизм означает, что вы можете вызвать метод overriden в суперклассе.
источник
Переопределяющий метод НЕ должен генерировать проверенные исключения, которые являются новыми или более широкими, чем те, которые были объявлены переопределенным методом.
Пример:
источник
Переопределяющий метод НЕ должен генерировать проверенные исключения, которые являются новыми или более широкими, чем те, которые были объявлены переопределенным методом.
Это просто означает, что когда вы переопределяете существующий метод, исключение, которое генерирует этот перегруженный метод, должно быть либо тем же исключением, что и исходный метод, либо любым из его подклассов .
Обратите внимание, что проверка того, все ли отмеченные исключения обработаны, выполняется во время компиляции, а не во время выполнения. Таким образом, во время самой компиляции компилятор Java проверяет тип исключения, которое генерирует переопределенный метод. Поскольку решение о том, какой переопределенный метод будет выполняться, можно решить только во время выполнения, мы не можем знать, какое исключение мы должны поймать.
пример
Допустим, у нас есть класс
A
и его подклассB
.A
имеет метод,m1
а классB
переопределил этот метод (позвольте вызвать его,m2
чтобы избежать путаницы ..). Теперь скажемm1
throwsE1
иm2
throwsE2
, который являетсяE1
суперклассом пользователя. Теперь напишем следующий фрагмент кода:Обратите внимание, что
m1
это не что иное, как вызовm2
(опять же, сигнатуры методов одинаковы в перегруженных методах, поэтому не путайте сm1
иm2
... они просто для различения в этом примере ... они оба имеют одинаковую сигнатуру). Но во время компиляции все, что делает компилятор java, - это обращение к ссылочному типу (A
в данном случае Class ), проверяет метод, если он присутствует, и ожидает, что программист обработает его. Так что, очевидно, бросишь или поймаешьE1
. Теперь, во время выполнения, если перегруженный метод выдаетE2
, который являетсяE1
суперклассом, тогда ... ну, это очень неправильно (по той же причине, которую мы не можем сказатьB myBObj = new A()
). Следовательно, Java этого не позволяет. Непроверенные исключения, создаваемые перегруженным методом, должны быть такими же, подклассами или отсутствовать.источник
Чтобы понять это, давайте рассмотрим пример, в котором у нас есть класс,
Mammal
который определяетreadAndGet
метод, который читает некоторый файл, выполняет с ним некоторую операцию и возвращает экземпляр классаMammal
.Класс
Human
расширяет классMammal
и переопределяетreadAndGet
метод для возврата экземпляраHuman
вместо экземпляраMammal
.Чтобы вызвать,
readAndGet
нам нужно будет обработать,IOException
потому что это проверенное исключение, и млекопитающееreadAndMethod
выбрасывает его.И мы знаем, что компилятор
mammal.readAndGet()
вызывается из объекта класса,Mammal
но во время выполнения JVM разрешитmammal.readAndGet()
вызов метода вызову из класса,Human
потому чтоmammal
он удерживаетсяnew Human()
.Метод
readAndMethod
отMammal
бросает ,IOException
и потому , что это проверяется компилятор исключения заставит нас поймать его всякий раз , когда мы вызываемreadAndGet
наmammal
Теперь предположим, что
readAndGet
inHuman
выбрасывает любое другое проверенное исключение, например Exception, и мы знаем, что оноreadAndGet
будетHuman
вызвано из экземпляра, потому чтоmammal
удерживаетсяnew Human()
.Поскольку для компилятора метод вызывается из
Mammal
, поэтому компилятор заставит нас обрабатывать только,IOException
но во время выполнения мы знаем, что метод будет генерироватьException
исключение, которое не обрабатывается, и наш код сломается, если метод вызовет исключение.Вот почему это предотвращается на уровне самого компилятора, и нам не разрешается генерировать какое-либо новое или более широкое проверенное исключение, потому что оно не будет обработано JVM в конце.
Есть и другие правила, которым мы должны следовать при переопределении методов, и вы можете прочитать больше о том, почему мы должны следовать правилам переопределения методов, чтобы узнать причины.
источник
Какое объяснение мы приписываем нижеприведенному
Класс DerivedClass.java генерирует исключение времени компиляции, когда метод печати генерирует исключение, метод print () базового класса не генерирует никаких исключений
Я могу связать это с тем, что Exception уже, чем RuntimeException, это может быть либо No Exception (ошибка времени выполнения), либо RuntimeException и их дочерние исключения
источник
Метод переопределения подкласса может генерировать только несколько проверенных исключений, которые являются подклассами проверенного исключения метода суперкласса, но не может генерировать несколько проверенных исключений, которые не связаны с проверяемым исключением метода суперкласса
источник
Java дает вам возможность ограничить исключения в родительском классе, поскольку предполагается, что клиент будет ограничивать то, что перехватывается . ИМХО вам, по сути, никогда не следует использовать эту «функцию», потому что вашим клиентам может потребоваться гибкость в будущем.
Java - это старый язык, который плохо спроектирован. В современных языках таких ограничений нет. Самый простой способ обойти этот недостаток - сделать ваш базовый класс
throw Exception
всегда. Клиенты могут выдавать более конкретные исключения, но делать ваши базовые классы действительно широкими.источник
Правило обработки проверенных и непроверенных исключений для переопределенных методов
- Когда метод родительского класса не объявляет исключения, тогда метод переопределения дочернего класса может объявить ,
-Когда метод родительского класса объявляет непроверенное исключение, тогда метод переопределения дочернего класса может объявить ,
- Когда метод родительского класса объявляет проверенное исключение, тогда метод переопределения дочернего класса может объявить ,
Все вышеприведенные выводы верны, даже если в методе родительского класса объявлено сочетание отмеченного и непроверенного исключения.
Ссылка
источник