意外的未经检查的转换警告

时间:2013-05-01 16:47:12

标签: java generics

任何人都可以解释为什么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 );
    }
}

3 个答案:

答案 0 :(得分:6)

b的类型为Entity,这是一种原始类型。因此它的API看起来像这样:

public Entity typed(Class type)

因此,您要从Entity转换为Entity<Integer>。编译器丢失了type参数与返回的实体类型之间的任何关联,因此无法进行任何检查。

换句话说,您可以使用:

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

...仍然只收到相同的警告。如果您使用xz尝试相同的更改,则会收到编译时错误。

编辑:正如评论中所述,您使用原始类型的事实会删除所有泛型的痕迹。

来自JLS section 4.8

  

为了便于与非泛型遗留代码接口,可以使用参数化类型(第4.5节)的擦除(第4.6节)或者元素类型为的数组类型(第10.1节)的擦除作为类型。参数化类型。这种类型称为原始类型。

然后在section 4.6

  

类型擦除还将构造函数或方法的签名(第8.4.2节)映射到没有参数化类型或类型变量的签名。构造函数或方法签名的擦除是一个签名,由与s相同的名称和s中给出的所有形式参数类型的擦除组成。

答案 1 :(得分:1)

来自宣言:

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

a,因此也会键入方法调用a.typed( Integer.class )

typed( b, Integer.class )中它起作用,因为该方法是通用的。

但是在

final Entity b = (Entity) a;

您已使用raw-type而不是b的泛型版本关闭了泛型(Entity),因此调用b.typed( Integer.class )是无类型的。所以你得到警告。

答案 2 :(得分:0)

您正在“向下转发”a,在分配给b时删除它的类型标识符。因为b现在是无类型的,所以你得到一个无类型转换警告,因为它不再知道类型。