java.lang.Class泛型和通配符

时间:2015-05-07 01:09:18

标签: java generics bounded-wildcard

为什么以下代码无法编译?

interface Iface<T> { }

class Impl<T> implements Iface<T> { }

class TestCase {
    static Class<? extends Iface<?>> clazz = Impl.class;
}

错误是

  

java:不兼容的类型:java.lang.Class<Impl>无法转换为java.lang.Class<? extends Iface<?>>

但我不明白为什么通配符无法捕获。

2 个答案:

答案 0 :(得分:3)

这里的子类型关系是:

          Class<? extends Iface>
           ╱                  ╲
Class<? extends Iface<?>>   Class<Impl>

(我在对'Cannot convert from List<List> to List<List<?>>'的回答中解释过。)

所以基本上它没有编译,因为它是一个横向转换。

如果可能,你可以进行我在那里描述的演员:

(Class<? extends Iface<?>>)(Class<? extends Impl>)Impl.class

如果你不能进行演员表演,那么你可能只需要处理原始有界Class<? extends Iface>。令人烦恼的主要原因是警告,但它开启了出错的可能性:

interface Iface<T> {
    void accept(T a);
}

class Impl2 implements Iface<String> {
    public void accept(String a) { }
}

class TestCase {
    static Class<? extends Iface> clazz = Impl2.class;

    public static void main(String[] args) throws Exception {
        // throws ClassCastException
        clazz.newInstance().accept(new Object());
    }
}

不太可能发生,但这取决于我想做的事情。

我倾向于认为这是Java类型系统的一个问题。

  • 可能应该有一个特殊规则,即类型参数? extends T<?>包含类型参数? extends T,例如Class<? extends T>转换为Class<? extends T<?>>。从定义子类型的现有方式的角度来看,这是没有意义的(TT<?>的超类型),但从类型安全的角度来看它是有意义的。

  • 或者例如List.class应该是Class<List<?>>而不是Class<List>

  • 或者其他一些比我更聪明的聪明人可以想到。

我上面描述的ClassCastException的有趣之处在于它完全是人为的。事实上,使用未经检查的演员表来阻止它会引发警告。

我想,只是表明Java中的泛型尚未完成。

答案 1 :(得分:1)

由于type-erasure,当您说Impl.class时,您会得到Class<Impl>。也就是说,你可以说

Class<Impl> clazz = Impl.class;

泛型是编译时类型安全功能。