Страницы

Поиск по вопросам

суббота, 8 февраля 2020 г.

Явное приведение типов

#java


Каким образом работает явное приведение типов то есть например:

List coll = new ArrayList();
List coll2 = (LinkedList) coll;


Явное приведение типа ArrayList к типу LinkedList как это происходит? Ясно что List
является общим интерфейсом для обоих поэтому ссылка может содержать объект типа ArrayList
или LinkedList или какую нибудь другую собственную реализацию...

Объясните пожалуйста каким образом происходит приведение типа ведь объект создается
в куче и как потом меняется его тип?
    


Ответы

Ответ 1



Такое приведение типов не сработает и будет выброшено исключение. ArrayList нельзя привести к типу LinkedList. Смотрите дерево подчиненности. Касательно самой операции приведения типов (или cast'а) - исходный объект - тип не меняет, просто меняется ссылка на него. P.S. Подтекст вопроса в том, что якобы ваш col1 имеет тип List, а раз он имеет тип List то можно провести кастинг на LinkedList, который также имеет интерфейс List. Хитрый у вас интервьюер :) Update Правила кастинга такие: Downcasting - нисходящее приведение, то есть приведение от предка к потомку предку подтипу возможно если только исходная переменная является подтипом приводимого типа. Ошибка может возникать runtime или на этапе компиляции. Скажем: Object object; String s=(String )object; //разрешено, поскольку тип переменной object //может быть String'ом, но это выяснится только в runtime Double object=new Double(1.0); String s=(String )object; //ошибка будет на этапе компиляции поскольку тип // object известен компилятору и он не приводим к типу String Object object=new Double(1.0); Number n=(Number )object; //разрешено, поскольку Double // является подтипом Number Upcasting - восходящее приведение типов или приведение типов от потомка к предку, разрешено всегда. Запрещено приведение типов не "лежащих" в одной иерархии (как в случае Double и String или LinkedList и ArrayList)

Ответ 2



Предыдущий оратор достаточно полно описал нисходящее преобразование, но восходящее (на мой взгляд) требует дополнительных пояснений, так как вопрос очень популярен и интересен. Каким образом работает явное приведение типов В вашем примере показано восходящее преобразование (Upcasting): List coll = new ArrayList(); На русский язык переводится так: создай ворону, типа птицы. Создай динамический массив, типа лист. В большинстве ситуаций восходящее преобразование совершенно не нужно. Однако, приведение типов работает на собеседованиях, когда вам дают вопросы на наследование. К примеру, сайт quizful.net вообще содержит в себе множество вопросов на приведение типов. Поэтому разъясню особенности, которые знаю. Итак, в вышеприведенном примере мы создали объект типа ArrayList, а ссылка типа List. Запомните аксиомы для этого способа: 1. Ссылку можно указать на любого родителя. Даже очень давнего. То есть, можно привести ссылку coll даже к типу Object. Компилятор пропустит любую ссылку на класс родителя, или родителя-родителя, или родителя-родителя...родителя 2. Обращение к полю - всегда идёт возврат поля ссылки, не поля объекта. Если такого поля нет в классе-ссылке будет ошибка компиляции. Class A{ int x = 2; //Поле родителя } Class B extends A { int x = 3; //Поле которое должно перекрыть родительское int y = 5; //Поле, которого нет в родительском классе. } Class Test{ public static void main(String[] args) { A ab = new B(); //Восходящее преобразование System.out.println("Int x = " + ab.x); } } Вернет Int x = 2. Если вы попробуете обратиться к полю объекта: System.out.println("Int y = " + ab.y); //Ошибка компилляции Ваш компилятор скажет, что вы не правы, так как он по ссылке (A ab) не видит такого поля. Всё вышесказанное сохраняет силу, даже если ваши поля пометить модификаторами static. 3. Обращение к нестатическому методу: в этом случае вернёт метод объекта. Но при обращении к статическому методу - возвращает метод ссылки. class D{ public void doSome(){ //Нестатический метод System.out.println("Nonstatic doSome from D"); } public static void Action(){ //Статический метод System.out.println("static Action from D"); } } public class Okey extends D{ public void doSome(){ System.out.println("doSome from Okey"); } public static void Action(){ System.out.println("static Action from Okey"); } public static void main(String[] args) { D o=new Okey(); o.doSome(); //Из класса Okey o.Action(); //Из класса D } } Вывод: Nonstatic doSome from Okey static Action from D Разгадка проста, нестатический метод - это метод объекта, статический - метод класса. Когда мы вызываем не статический метод - компилятор понимает так: летай как ворона. Когда мы вызываем статический - буквально, летай как птица. 4. Если идёт вызов метода, который описан в классе объекта, но не описан в классе ссылки - пойдёт ошибка компилляции. Потому что, вызов метода происходит по ссылке: Class A {} Class B extends A { void someMethod(){}; public static void main(String[] args) { A ab = new B(); ab.someMethod(); //Ошибка компилляции. } } Компилятор такой, пойдёт по ссылке попадёт в класс A - глядь, а метода someMethod() нету! И заругается. 5. Конструктор объекта (при создании командой new) работает также, как если давать ссылку на свой класс.

Комментариев нет:

Отправить комментарий