При переопределении унаследованного метода или реализации метода абстрактного класса не позволяется задавать в предложении throws нового метода больше объявляемых исключений, чем в исходном методе.
Исключением может быть ситуация, когда список объявляемых исключений дополняется классом, родительский класс которого был объявлен в родительском методе, т.е. формально новый тип исключения при этом не добавляется. Вообще говоря, переопределенный метод должен сохранить контракт родительского: с одной стороны, он может и не объявлять исключения, объявленные в родительском методе, с другой стороны, он не может объявить тип исключения, который не может быть приведен к одному из типов, объявленных в родительском методе.
Предложения throws и методы native
В объявление метода native может быть включено предложение throws, которое заставляет код, вызывающий метод, отлавливать или переопределять указанные объявляемые исключения. Однако реализация native-методов находится вне компетенции компилятора Java, который поэтому не в состоянии проверить, действительно ли код метода выбрасывает только те исключения, которые им объявлены.
Try , catch и finally
Исключения могут быть отловлены, если требуемый фрагмент кода заключить в блок try, синтаксис которого выглядит так:
try {
Инструкции – тело блока
} catch (Тип исключения 1 идентификатор 1) {
Инструкции – обработка исключения
} catch (Тип исключения 2 идентификатор 2) {
Инструкции – обработка исключения
…
} finally {
Инструкции
}
Тело блока try выполняется до момента возникновения исключительной ситуации либо благополучного достижения конца кода блока. Если в процессе работы выбрасывается исключение – либо непосредственно, командой throw, либо косвенно, при вызове какого-либо метода – работа блока try прекращается и система последовательно проверяет все предложения catch, пытаясь найти среди них то, тип которого допускает присваивание объекта выброшенного исключения. Если искомое предложение catch найдено, ему в качестве аргумента передаётся объект исключения, после чего выполняется блок кода этого предложения. Другим предложениям catch управление не передаётся. Конструкция try может содержать любое количество предложений catch либо не содержать таковых вовсе, а каждое предложение catch способно отлавливать исключения различных типов. Если соответствующее предложение catch не найдено, исключение передаётся последовательно во внешние блоки try, в которых может быть найден требуемый код catch.
Предложение catch чем-то напоминает «встроенный метод», обладающий единственным параметром типа исключения, подлежащего обработке. Код catch способен выполнить некие восстановительные операции, выбросить собственное исключение, вручая полномочия по обработке ошибки внешнему коду, либо осуществить всё необходимое, а затем передать управление инструкции, следующей за try (после выполнения блока finally, если таковой имеется).
Задание в предложении catch параметра, относящегося к общему типу исключений (таковому, например, как Exception) – это обычно не очень правильный выбор, поскольку такое предложение способно отлавливать любые исключения, а не только те, которые относятся к исключениям производных типов, рассматриваемым в конкретной ситуации.
Предложение catch, содержащее в качестве параметра один из базовых типов исключений, не может быть расположено перед теми catch, в которых заданы соответствующие производные типы. Предложения catch просматриваются системой поочерёдно, поэтому размещение в начале последовательности тех из них, которые относятся к базовым типам, воспрепятствует передаче управления остальным (см. пример 22).
Пример 22.
class SuperException extends Exception {
// Базовый класс исключений
}
class SubException extends SuperException {
// Производный класс исключений
}
class BadCatch {
public void goodTry () {
// Последовательность предложений catch неверна
try {
throw new SubException();
} catch (SuperException superRef) {
// Ловит и SuperException, и SubException
} catch (SubException subRef) {
// Код недостижим
}
}
}
Конкретный блок try в ходе выполнения может сгенерировать только одно исключение. Если в предложениях catch или finally выбрасываются другие исключения, предложения catch текущей конструкции try заново не проверяются. Но ничто не запрещает обрабатывать такие исключения с помощью вложенных конструкций try …catch…finally.
Если в конструкции try присутствует предложение finally, его код выполняется по завершении работы остальных фрагментов кода try. Это происходит независимо от того, каким образом протекал процесс вычислений – успешно, с выбрасыванием исключения либо с передачей управления посредством команды return или break. Обычно блок finally используется для осуществления операций очистки внутреннего состояния объекта или высвобождения ресурсов, не связанных со свободно распределяемой памятью, таких как, например, дескрипторы открытых файлов, хранимые в локальных переменных. Предложения finally используются и в тех случаях, когда необходимо осуществить ряд завершающих операций после выполнения инструкций break, continue или return, - вот почему нередко применяются такие конструкции try, в которых отсутствуют предложения catch.
При передаче управления в блок finally предварительно сохраняется информация о причине окончания выполнения блока try – код был исчерпан естественным образом либо завершен принудительно с помощью одной из управляющих инструкций, таких как return, или сгенерированного исключения. Эта информация восстанавливается в момент выхода из блока finally. Если, однако, код finally обладает собственными полномочиями по передаче управления во внешний блок посредством инструкций break или return либо выбрасывания исключения, исходная причина «забывается» и замещается новой (см. пример 23).
Пример 23.
try {
// Что-то присходит
return 1;
} finally {
return 2;
}
При выполнении кодом try команды return блоку finally передаётся управление и информация о причине завершения try – инструкция return возвратила значение 1. Код finally , в свою очередь, также выполняет команду return , но теперь она возвращает другое значение – 2, и исходное «намерение» системы заменяется новым. Если в процессе выполнения кода try будет выброшено исключение, итогом всё равно окажется, разумеется, инструкция return 2. Но если бы блок finally не содержал этой инструкции, первоначальная цель – «возвратить с помощью команды return значение 1» – была бы реализована.
Наследование
Одно из основных преимуществ ООП состоит в возможности наследования (inheritance), или расширения (extending) функционального потенциала базового (родительского - superclass) класса при построении на его основе производного (дочернего - subclass) класса. Объект нового класса допускается применять в любом контексте, где предусмотрено использование экземпляров исходного класса. Последняя возможность носит название полиморфизма и означает, что определённый класс способен восприниматься либо сам по себе, либо в качестве любого из исходных классов, которые он наследует.
Набор методов и полей класса, открытых для свободного доступа извне, в совокупности с описанием их назначения называют контрактом класса. Контракт – это способ выражения обещаний автора относительно того, на что способен и для чего предназначен созданный им продукт. Существуют две формы практического воплощения концепции наследования:
· наследование контракта или типа, в результате чего производный класс получает тип базового и поэтому может быть использован полиморфным образом во всех случаях, где допустимо применение базового класса;
· наследование способов реализации – производный класс приобретает функциональные характеристики базового в виде набора доступных полей и методов.
Очень часто инструменты наследования используются для обеспечения возможности специализации, когда производный класс становится специализированной версией базового класса. В процессе наследования в новом классе может быть предусмотрено, например, изменение способа реализации какого-то метода с целью достижения большей эффективности. При решении задачи расширения класса обе названные выше формы наследования всегда рассматриваются совместно.
Дата: 2019-02-19, просмотров: 245.