意外类型擦除

时间:2013-11-04 16:50:15

标签: java generics type-erasure

我遇到了泛型问题,而我认为是类型擦除问题,同时试图反映一些通用信息。

我正在使用基于http://www.artima.com/weblogs/viewpost.jsp?thread=208860的课程进行反思,但这不是问题。

下面的代码演示了这个问题:

private <U extends MyClass1> U doSomething(MyClass2<U> p) {
     Class<U> classIWant = null;
     for (Class<?> c : GenericTypeUtils.getTypeArguments(MyClass2.class, p.getClass()))      {
        if (MyClass1.class.isAssignableFrom(c)) {
            classIWant = c.asSubclass(MyClass1.class);
            break;
        }
    }
}

不幸的是行

classIWant = c.asSubclass(MyClass1.class);

显示以下错误

java: incompatible types
  required: java.lang.Class<U>
  found:    java.lang.Class<capture#4 of ? extends MyClass1>

这真让我感到困惑。 U扩展了MyClass1,因此U是MyClass1。

显然有一些类型的擦除我不明白 - 请有人帮忙。 BTW这是Java 1.7.0_40

由于

康拉德温彻斯特

2 个答案:

答案 0 :(得分:1)

方法asSubclass()的实现方式如此

public <U> Class<? extends U> asSubclass(Class<U> clazz) {
    if (clazz.isAssignableFrom(this))
        return (Class<? extends U>) this;
    else
        throw new ClassCastException(this.toString());
}

返回类型为Class<? extends U>。请注意,U方法中的UasSubclass是完全不相关的类型变量。

因此,方法asSubclass()返回使用某个未知子类型Class的类型U声明的值,其中U在这种情况下为MyClass1

您正尝试将此值分配给Class类型的变量,其中已知子类型为MyClass1。编译器不能保证它们匹配,因此不允许编译。

如果您愿意,可以强制转换返回的值,但如果类型不匹配,最终可能会在运行时获得ClassCastException

答案 1 :(得分:1)

Java编译器无法保证Class对象c与泛型U匹配。由于类型擦除,编译器需要保证类型安全,并确保从Class返回的c.asSubclassClass<U>匹配,但不能。{/ p>

The asSubclass method返回Class<? extends U>。在Class班级中,U表示传递给Class的{​​{1}}类型。当你打电话时,那是asSubclass。但编译器无法保证此返回类型与您自己声明的c匹配。它们可以是<U extends MyClass1>的不同子类。

如果可以保证MyClass1会返回c.asSubclass,那么将其投放为Class<U>

Class<U>

您将收到“未经检查的演员”警告。这是因为编译器不能保证它确实是classIWant = (Class<U>) c.asSubclass(MyClass1.class); ,但你说的是它。请注意,即使在您返回Class<U>之后,这可能会导致其他地方难以追踪ClassCastException。只有在您可以自己保证类型安全的情况下才能这样做。