Приведение ссылочных типов

В предыдущих уроках мы рассматривали преобразование примитивных типов. В этом разделе рассмотрим какие существуют варианты приведения ссылочных типов в языке Java. В общем выделяют два варианта - это сужение и расширение.

  1. Расширение типов в Java
  2. Сужение типов в Java
  3. Оператор instanceof в Java
  4. Несовместимые преобразования в Java
  5. Преобразование типов для массивов

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 CastingDemo1 {
    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 CastingDemo2 {
    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 CastingDemo3 {
    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 ArrayCastingDemo1 {
    public static void main(String[] args) {
        int[] array = new int[5];
        //int someNumber =array;
        int someNumber = array[0];
    }
}

5.2. Примитивные и ссылочные массивы

Массив, основанный на примитивном типе, принципиально нельзя преобразовать к типу массива, основанному на ссылочном типе, и наоборот:

public class ArrayCastingDemo2 {
    public static void main(String[] args) {
        Integer[] array1 = new Integer[4];
        int[] array2 = new int[4];
        //  array1 = array2;
        //  array2 = array1;
    }
}

5.3. Массивы основанные на разных примитивных типах

Преобразования между типами массивов, основанных на различных примитивных типах, невозможно:

public class ArrayCastingDemo3 {
    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 ArrayCastingDemo5 {
    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 ArrayCastingDemo4 {
    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 ArrayCastingDemo6 {
    public static void main(String[] args) {
        HeavyBox1[] heavyBox = new HeavyBox1[4];
        Box6[] box = heavyBox;
        box[0] = new Box6(); //ArrayStoreException
    }
}
Read also:
Comments