1. Приведение типов
Переменные ссылочных типов (классов) тоже можно преобразовывать к разным типам. Однако это работает только в рамках одной иерархии типов. Давайте рассмотрим на простом примере. Допустим, у нас есть такая иерархия классов: классы ниже наследуются от классов выше.

Приведение ссылочных типов, как и примитивных тоже делится на расширяющие и сужающее.
Мы видим, что класс Кот унаследован от класса ДомашнееЖивотное, а класс ДомашнееЖивотное в свою очередь от класса Животное.
Если мы напишем такой код:
Животное котик = new Кот();
Это расширяющее приведение типа: его еще называют неявным. Мы расширили ссылку котик, и теперь она ссылается на объект типа Кот. При таком приведении мы не сможем через ссылку котик вызвать методы, которые есть у класса Кот, но которых нет у класса Животное.
Сужающее приведение (или явное) происходит в обратную сторону:
Кот котэ = (Кот) котик;
Мы явно указали, что хотим привести ссылку, которая хранится в переменной котик (типа Животное) к типу Кот.
2. Проверка типа объекта
Но тут нужно быть очень осторожным. Если вы сделаете так:
Животное зверь = new Кот();
Волк серыйВолк = (Волк) зверь;
Компилятор пропустит этот код, а вот во время выполнения программы возникнет ошибка! JVM кинет вам исключение:
Exception in thread "main" java.lang.ClassCastException: Кот cannot be cast to Волк
Ссылку на объект Кот можно сохранить только в переменные, которые имеют тип класса-родителя для класса Кот: ДомашнееЖивотное, Животное и Object.
Почему же так?
Все дело в том, что ссылка на объект используется для того, чтобы обращаться к методам и переменным этого объекта. И если мы сохраним в переменную типа Животное ссылку на объект Кот, то никаких проблем с этим не возникнет: у типа Кот всегда будет переменная и методы типа Животное: он же их унаследовал!
А вот если бы JVM разрешила сохранить ссылку на объект Кот в переменную типа Волк, могла бы возникнуть ситуация, когда у переменной серыйВолк вызывается метод, который отсутствует у объекта Кот, на который эта переменная и ссылается. Поэтому такое сохранение не разрешается.
В Java есть специальный оператор — instanceof
, который позволяет проверить, можно ли сохранить объект определенного типа в переменную определенного типа. Выглядит он достаточно просто:
переменная instanceof Тип
Пример:
Животное зверь = new Кот();
if (зверь instanceof Волк)
{
Волк серыйВолк = (Волк) зверь;
}
Такой код не вызовет ошибок даже во время выполнения.
Вот еще несколько примеров с описанием ситуации:
Расширение типа | Описание |
---|---|
|
Классическое расширение типа — оператор преобразования типа не требуется. Теперь у объекта типа Компилятор разрешит вызвать у переменной |
Сужение типа | |
|
Классическое сужение типа: нужно добавить проверку типа и оператор приведения типа.
Переменная cow типа Cow хранит ссылку на объект класса Whale .
Мы проверяем, что это так и есть, и затем выполняем операцию преобразования (сужение) типа. Или как ее еще называют — type cast
.
|
|
Ссылочное сужение типа можно провести и без проверки типа объекта.
При этом, если в переменной cow хранился объект не класса Whale , будет сгенерировано исключение — InvalidClassCastException .
|
3. Вызов оригинального метода: super
Иногда бывает нужно не заменить метод родительского класса на свой при переопределении метода, а лишь немного дополнить его.
Было бы классно, если бы мы могли в нашем методе вызвать такой же метод родительского класса, а потом еще выполнить какой-то свой код. Ну или сначала выполнить свой код, а потом вызвать метод родительского класса.
И такая возможность в Java есть. Вызов метода именно родительского класса делает так:
super.метод(параметры);
Примеры:
class МирноеВремя
{
public double getPi()
{
return 3.14;
}
}
class ВоенноеВремя extends МирноеВремя
{
public double getPi()
{
return super.getPi()*2; // 3.14*2
}
}
В военное время значение Pi
может достигать четырех, а в нашем случае вообще 6! Это, конечно, шутка, но она демонстрирует, как это все может работать.
Вот еще пара примеров, чтобы немного прояснить ситуацию:
Код | Описание |
---|---|
|
Классы Cow и Whale
|
|
На экран будет выведена надпись:
|
Да, это непростой материал: честно говоря, он один из самых сложных в ООП. Однако знать и понимать его необходимо.