2017-02-09 11 views
1

Перейти к последнему предложению, если вы хотите сразу же прочитать вопрос.Понимание множественного литья в Java

Предположим, что у нас есть интерфейс и три класса:

interface I{} 

class A implements I{} 

class B extends A {} 

И следующие объявления:

A a = new A(); 
B b = new B(); 

Теперь, есть классический способ литья, который позволяет мне бросить ссылку типа A (родительский класс) объекту типа B (дочерний класс):

a = b; //here a is no longer pointing at object A, and is now pointing at the same object b is pointing at. 
b = (B) a; // the casting is now accepted by the compiler and during runtime as well. 

Здесь, где лежит проблема, хотя. Каждый раз, когда я вижу строку кода с несколькими кастами, я не читаю ее (буквально), и, как результат, я не могу понять, что это значит.

Например, скажем, у нас есть эта строка кода:

a = (B)(I)b; 

Как бы вы читали это? a - это ссылка на объект типа A, которому присваивается значение объекта типа B (сначала сбрасывается слева). Но подождите минуту, есть еще один актер (I), предшествующий b. Итак, что мы здесь имеем? Является ли это интерфейсом как объект (B)? или это b, будучи отлитым как интерфейс, который также отливается как (B)?

Я попытался разбить его, чтобы избежать путаницы:

I temp = (I) b;// first line 
a = (B) temp;// second line 

Итак, сначала, так как б это я (потому что он расширяет, который реализует I), «первая линия» принимается компилятором и во время выполнения.

«Вторая строка», хотя мы имеем ссылку на объект A, которому присваивается значение типа B. На первый взгляд нет ничего плохого в этом. Но потом я понял, что I не является A и не является B, и даже если приведение в «второй строке» может обмануть компилятор, полагая, что это объект типа B, его нельзя принимать во время выполнения.

Так что главный вопрос, который я хотел бы получить ответ на то, как интерпретировать следующую строку:

a = (B)(I)b; 
+3

я бы интерпретировать его как два ненужных слепков. –

+1

Кастинг для интерфейса просто кажется неправильным. – Aziuth

+0

'I' не' B', но 'I' может быть' B' :) – ZhongYu

ответ

0
a = (B)(I)b; 

Cast b к I, а затем привести его к B. Предположительно, поскольку вы не можете напрямую наложить b на B.

В настоящее время на самом деле нет хороших ситуаций, которые необходимо использовать, поскольку, по возможности, следует избегать приведения даже одного раза. Однако, если вы хотите что-то вроде

String s = (String) myHashMap; 

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

String s = (String) (Object) myHashMap; 

Естественно, если ваш myHashMap не имеет нулевое значения, это может привести к время выполнения ClassCastException, но в отличие от предыдущего примера оно будет скомпилировано.

+0

Но проблема в том, что {a = (B) (I) b;} также принимается во время выполнения. b IS-a I, поэтому нет проблем с этим приложением, но почему принимается I-я-B? Если я не ошибаюсь, я не являюсь примером использования –

+1

с двойным литьем: http://bayou.io/draft/Wildcard_Case_Studies.html#Casting_Between_Concrete_Types – ZhongYu

+1

@ZhongYu Исправить, хотя это должно быть исправлено путем изменения фактические общие типы с более широкой границей. – Kayaman

1

Основываясь на Java language grammar, заявление

a = (B)(I)b; 

может быть лучше визуализировать, как это:

a = 
    // outer CastExpression 
    (B)(
    // with its UnaryExpression being another CastExpression 
    (I)(b) 
); 

То есть, он бросает b к I, затем бросает, что B, затем присваивает к переменной A.

Однако, это не похоже на то, что любой из этих приводов необходим. Если b является экземпляром B, он также является экземпляром A и I.

4

или реальность Ответ вы не хотите

Реальная проблема здесь в том, что небрежное дурня написал дерьмовый код. Реальное решение; либо не писать дрянной код, либо исправить код.

Позволяет оставаться готовым к использованию или отвечать, как вам кажется В java есть два типа литья; литье под давлением и литье под давлением.

Подбрасывание - это когда вы бросаете объект типа A в качестве экземпляра интерфейса I; вы бросаете «вверх» дерево наследования. Например:

A aObject = new A(); 
I iObject = (I)aObject; // Up casting. 

Преимущество повышающего литья является то, что компилятор может определить, во время компиляции, если приведение является законным.

Литье под давлением - это когда вы бросаете объект типа I объектом типа A; вы бросаете «вниз» дерево наследования. Например:

A aObject; 
I iObject = new A(); 

aObject = (A)iObject; 

компилятор не знает, во время компиляции, если вниз литье получится. Из-за этого приведение может вызывать исключение во время выполнения.

Ваш вводящий в заблуждение код: a = (B)(I)b; является примером как для литья под давлением (безопасного), так и для литья под давлением (небезопасно).

В качестве бонуса литье не требуется. Всегда безопасно назначать объект B непосредственно для ссылки A, потому что класс B расширяет класс A.

Адресация: "неосторожный goofball" кажется сильным языком. Это не сильный язык, это самый приятный способ описать причину вашей ситуации. По правде говоря, кто-то, кто пишет такой код, должен быть прекращен (необязательно, чтобы нанять их одним из ваших конкурентов).

+0

Официальным термином Java для «upcast» является «расширяющееся преобразование», а для «downcast» - «сужение преобразования». С официальными терминами прямо искать правила в JLS. –

0

Возможно, вы не понимаете, что, даже если приведение к I или A, b остается объектом типа B, оно не теряет своей природы. Подумайте о том, чтобы сказать, что java «видит мой объект как объект типа I». Тогда, если тип B также относится к типу A.

Таким образом, инструкция указывает, что java использует мой объект, поскольку он относится к типу I, и сразу же после использования его как типа B, который по объявлению также имеет тип A. Таким образом, ошибки компиляции или времени выполнения отсутствуют.

Тогда мы можем see.that это выглядит также в основном неполезным и некрасиво ..

+0

Прошлое причастие на английском языке «cast» - «cast». –

+0

Aahh мой английский! – Massimo

+0

Не волнуйся, @ Массимо, ваш английский так же хорош, как почти каждый, кого я встречал в шести штатах США, которые я прожил, или дюжина или около того, которую я посетил. –