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 );
    }
}
4

3 回答 3

6

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

public Entity typed(Class type)

所以你正在从 转换EntityEntity<Integer>。编译器已经失去了type参数和返回的实体类型之间的任何关联,因此它无法进行任何检查。

换句话说,您可以使用:

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

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

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

JLS 第 4.8 节

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

然后在第 4.6 节中:

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

于 2013-05-01T16:53:13.577 回答
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 )是无类型的。所以你得到警告。

于 2013-05-01T16:53:37.657 回答
0

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

于 2013-05-01T16:53:24.640 回答