Class <list>或Class <list <?>&gt; </list <?> </list>

时间:2011-07-05 22:34:18

标签: java oop generics

如果我们有一个泛型类的变量,比如List,它应该是什么类型的?

List<Class> c1;

List<Class<?>> c2;  

3 个答案:

答案 0 :(得分:10)

第二个,因为第一个使用原始类型而不是泛型。

即。 List是原始的,但List<?>是通用的,您不应该在原始广告和通用广告之间进行混合匹配。

答案 1 :(得分:9)

您想表示运行时类或类型吗? (区别在于List<String>List<Integer>是不同的类型,但共享相同的运行时类。)

输入:使用类似type token的内容。

运行时类:自

    List<String> ls = new ArrayList<String>();
    Class<? extends List> c1 = ls.getClass();
    Class<List> c2 = List.class;

编译,但

    Class<? extends List<?>> c3 = ls.getClass();
    Class<List<?>> c4 = List.class;

没有,我选择在类型表达式中使用原始类型。指定List的类型参数确实没有任何好处,因为类没有确定它,并且使用通配符类型将需要奇怪的转换才能使其成为正确的类型,例如:

    Class<?> rawClass = List.class; // kludge: do not inline this variable, or compilation will fail
    Class<List<?>> classForBadAPI = (Class<List<?>>) rawClass;

编辑:为什么不编译

取消评论:

  

为什么第二个代码没有编译?代码非常有意义。这是JDK的设计错误吗?或者是否有正当理由选择?

List.class的类型为Class<List>。由于List<?>List是不同的类型,Class<List<?>>Class<List>是不相关的类型,但是赋值的右手类型必须是左手类型的子类型。 getClass()案例类似。

我不会责怪JDK,他们只实现了语言规范本身规定的规则,特别是:

  

类文字的类型C.Class,其中C是类,接口或数组类型的名称,为Class<C>

source

  

表达式e.getClass()具有静态类型e的方法调用T的类型为Class<? extends |T|>

source

  

我们为|T|类型的删除编写T

source

...为什么会这样定义?

  

编译器知道e的完整泛型类型,但为什么e.getClass()必须返回已删除的类型。

很难给出明确的答案,因为规范没有扩大该定义的原因。但是,这可能是因为运行时类型可能不是静态类型的子类型,这是由于未经检查的警告(c.f heap pollution)的错误抑制而导致的病态情况。通过指定返回类型仅包含擦除,规范确保即使存在堆污染,getClass()返回的类对象也是声明的返回类型getClass()的实例。它还提醒我们,程序员即将使用反射API访问的运行时只考虑擦除类型。

答案 2 :(得分:5)

Class<? extends List<?>>

由于List本身就是一个接口,这可能是一个更好的选择。