Приведение ссылочных типов
В предыдущих уроках мы рассматривали преобразование примитивных типов. В этом разделе рассмотрим какие существуют варианты приведения ссылочных типов в языке Java. В общем выделяют два варианта - это сужение и расширение.
- Расширение типов в Java
- Сужение типов в Java
- Оператор instanceof в Java
- Несовместимые преобразования в Java
- Преобразование типов для массивов
1. Расширение типов в Java
Первый вариант приведения - это расширение. Расширение означает переход от более конкретного типа к менее конкретному, то есть переход от детей к родителям.
Подобно случаю с примитивными типами, этот переход производится самой JVM при необходимости и незаметен для разработчика. Если класс Box
супер класс, а HeavyBox
- его наследник, то объект типа HeavyBox
можно неявно преобразовать к Box
:
Box heavyBox = new HeavyBox(15, 10, 20, 5);
Также расширяющим являются преобразованием от null-типа к любому объектному типу:
Box box = null;
2. Сужение типов в Java
Обратный переход, то есть движение по дереву наследования вниз, к наследникам, является сужением. Объект box
типа Box
приводим к HeavyBox
:
Box box = new HeavyBox();
HeavyBox heavyBox = (HeavyBox) box;
Следующий пример показывает зачем нужны сужающие преобразования.
Допустим переменная box1
типа Box6
указывает на объект типа HeavyBox1
(Box6
- это супер класс, HeavyBox1
- его наследник). Мы хотим вывести на консоль значение переменной класса weight
для объекта box1
. Но переменная weight
объявлена в классе HeavyBox1
, поэтому доступа к ней через box1
мы не имеем. Для того чтобы обратиться к весу, нам необходимо сделать приведение к HeavyBox1
: HeavyBox1 heavyBox1 = (HeavyBox1) box1
.
При попытке приведения переменной box2
, указывающей на объект типа ColorBox
, к HeavyBox1
, возникнет ошибка ClassCastException времени выполнения. ColorBox
тоже является наследником класса Box6
, поэтому ошибки компиляции не возникнет.
public class CastingExample1 {
public static void main(String[] args) {
Box6 box1 = new HeavyBox1();
// System.out.println(box1.weight);
HeavyBox1 heavyBox1 = (HeavyBox1) box1;
System.out.println("Вес: " + heavyBox1.weight);
Box6 box2 = new ColorBox();
HeavyBox1 heavyBox2 = (HeavyBox1) box2; //ClassCastException
Box6 box3 = new Box6();
HeavyBox1 heavyBox3 = (HeavyBox1) box3; //ClassCastException
}
}
3. Оператор instanceof в Java
public class CastingExample2 {
public static void main(String[] args) {
Box6 box1 = new HeavyBox1();
if (box1 instanceof HeavyBox1) {
System.out.println("Приведение 1");
}
if (box1 instanceof Box6) {
System.out.println("Приведение 2");
}
if (box1 instanceof Object) {
System.out.println("Приведение 3");
}
Box6 box2 = new ColorBox();
if (box2 instanceof HeavyBox1) {
System.out.println("Приведение 4");
}
Box6 box3 = new Box6();
if (box3 instanceof HeavyBox1) {
System.out.println("Приведение 5");
}
}
}
public class CastingExample3 {
public static void main(String[] args) {
Moveable moveable1 = new Transport();
if (moveable1 instanceof Transport) {
Transport transport = (Transport) moveable1;
transport.start();
}
Moveable moveable2 = new Robot();
if (moveable2 instanceof Transport) {
Transport transport = (Transport) moveable1;
transport.stop();
}
}
}
4. Несовместимые преобразования в Java
Преобразования возможны только внутри одной иерархии.
Данный пример не откомпилируется:
Box6 box1 = new HeavyBox1();
String str = (String) box1;
5. Преобразование типов для массивов
5.1. Массивы и примитивные типы
Переходы между массивами и примитивными типами являются запрещенными:
public class ArrayCastingExample1 {
public static void main(String[] args) {
int[] array = new int[5];
//int someNumber =array;
int someNumber = array[0];
}
}
5.2. Примитивные и ссылочные массивы
Массив, основанный на примитивном типе, принципиально нельзя преобразовать к типу массива, основанному на ссылочном типе, и наоборот:
public class ArrayCastingExample2 {
public static void main(String[] args) {
Integer[] array1 = new Integer[4];
int[] array2 = new int[4];
// array1 = array2;
// array2 = array1;
}
}
5.3. Массивы основанные на разных примитивных типах
Преобразования между типами массивов, основанных на различных примитивных типах, невозможно:
public class ArrayCastingExample3 {
public static void main(String[] args) {
int[] array1 = new int[5];
long[] array2 = new long[5];
// array2 = array1;
}
}
5.4. Ссылочные массивы основанные на типах из одной иерархии
Массив, основанный на типе HeavyBox
, можно привести к массиву, основанному на типе Box
, если сам тип HeavyBox
приводится к типу Box
.
public class ArrayCastingExample5 {
public static void main(String[] args) {
rightConversion();
wrongConversion();
}
private static void rightConversion() {
Box6[] boxArray = new Box6[5];
HeavyBox1[] heavyBoxArray = new HeavyBox1[6];
boxArray = heavyBoxArray;
}
private static void wrongConversion() {
Box6[] boxArray = new Box6[5];
HeavyBox1[] heavyBoxArray = new HeavyBox1[6];
//ошибка времени выполнения
heavyBoxArray = (HeavyBox1[]) boxArray;
}
}
5.5. Массивы и другие ссылочные типы
Преобразования между массивами и другими объектными типами возможны только для класса Object
и интерфейсов Cloneable
и Serializable
.
public class ArrayCastingExample4 {
public static void main(String[] args) {
Box6[] array = new Box6[5];
Object object = array;
Cloneable cloneable = array;
Serializable serializable = array;
}
}
5.6. Ошибка ArrayStoreException
public class ArrayCastingExample6 {
public static void main(String[] args) {
HeavyBox1[] heavyBox = new HeavyBox1[4];
Box6[] box = heavyBox;
box[0] = new Box6(); //ArrayStoreException
}
}
Зарегистрируйтесь или войдите, чтобы иметь возможность оставить комментарий.