2013-05-01 5 views
8

Может ли кто-нибудь объяснить, почему существует нетипизированное уведомление о преобразовании в строке назначения y? Обратите внимание, что нет никаких предупреждений о назначении x или z.Неожиданное предупреждение о непроверенной конверсии

public class Entity<T> 
{ 
    @SuppressWarnings("unchecked") 
    public <TX> Entity<TX> typed(Class<TX> type) 
    { 
     return (Entity<TX>) this; 
    } 

    @SuppressWarnings("unchecked") 
    public static <TX> Entity<TX> typed(Entity<?> entity, Class<TX> type) 
    { 
     return (Entity<TX>) entity; 
    } 

    public static void main(final String[] args) 
    { 
     final Entity<?> a = new Entity<Integer>(); 
     final Entity b = (Entity) a; 

     final Entity<Integer> x = a.typed(Integer.class); 
     final Entity<Integer> y = b.typed(Integer.class); 
     final Entity<Integer> z = typed(b, Integer.class); 
    } 
} 
+2

Ваша сущность, 'b', является нетипизированной после броска из' a', поэтому она нетипизируется, когда вы конвертируете ее с помощью 'b.typed (Integer.class)'.Общие типы не похожи на типы классов; они не сохраняются, когда «опущены». – Vulcan

ответ

6

b имеет тип Entity, который является исходным типом. Поэтому его API выглядит следующим образом:

public Entity typed(Class type) 

Так вы конвертируете из Entity в Entity<Integer>. Компилятор потерял какую-либо корреляцию между параметром type и видом возвращаемого объекта, поэтому он не может выполнять никаких проверок.

Иными словами, вы можете использовать:

final Entity<Integer> y = b.typed(String.class); 

... и до сих пор получают только такое же предупреждение. Если вы попробуете такое же изменение с x или z, вместо этого вы получите ошибку времени компиляции.

EDIT: Как отмечается в комментариях, тот факт, что вы используете необработанный тип, удаляет все следы дженериков.

От JLS section 4.8:

Для облегчения взаимодействия с необщим унаследованным кодом, можно использовать в качестве типа стирания (§4.6) параметризированного типа (§4.5) или стирания тип массива (§10.1), тип элемента которого является параметризованным типом. Такой тип называется сырым типом.

А потом в section 4.6:

Тип стирание также отображает подпись (§8.4.2) из ​​конструктора или методы для подписи, который не имеет параметризованные типов или типа переменных. Стирание конструктора или сигнатуры метода s является сигнатурой, состоящей из того же имени, что и s, и стираниями всех формальных типов параметров, указанных в s.

+1

Обратите внимание, что сам метод «набранный» сам параметризуется. Существует два типа параметров. –

+4

@KonstantinKomissarchik: Это не имеет значения - когда вы вызываете метод на сырой тип, все это уходит. –

+0

За исключением того, что компилятор не говорит, что я вызываю метод на необработанном типе. Он говорит, что я делаю непроверенное преобразование в присваивании от Entity to Entity . Тип, если он полностью указан TX. –

0

Вы являетесь "downcasting" a, удаляя его идентификатор типа при назначении b. Поскольку b теперь нетипизирован, вы получаете предупреждение о нетипизированном преобразовании, поскольку оно больше не знает тип.

1

Из декларации:

final Entity<?> a = new Entity<Integer>(); 

a набирается, так что вызов метода является a.typed(Integer.class) также набран.

В typed(b, Integer.class) это работает, потому что метод является общим.

Но в

final Entity b = (Entity) a; 

вы выключенные дженерик (для b с использованием забортного типа вместо родовой-версии Entity), поэтому вызов b.typed(Integer.class) является нетипизированным. Поэтому вы получите предупреждение.

Смежные вопросы