Class <List>或Class <List <?>>

irr*_*ble -9 java oop generics

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

List<Class> c1;
Run Code Online (Sandbox Code Playgroud)

要么

List<Class<?>> c2;  
Run Code Online (Sandbox Code Playgroud)

Meh*_*dad 10

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

List是原始的,但是List<?>是通用的,你不应该在原始和泛型之间混合搭配.

  • @irreputable:但是省略type参数会把它变成一个原始类型.[JLS第4.8节](http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.8)说"只允许使用原始类型作为对遗产兼容性的让步代码.强烈建议不要在将通用性引入Java编程语言后编写的代码中使用原始类型.**未来版本的Java编程语言可能会禁止使用原始类型.**" (3认同)
  • @irreputable:不,不.[javadoc](http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#getClass())表示返回`Class <?>`. (2认同)
  • @Mehrdad在下面读了两行:"**实际结果类型是Class <?extends | X |>**".如果返回类型确实是`Class <?>`,那么这不应该编译:`Class <Object> c = new Object().getClass()`因为我们不能将`Class <?>`分配给`Class <对象>`.但它确实编译,所以返回类型是**不是**`Class <?>` (2认同)

mer*_*ike 9

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

类型:使用类似标记之类的东西.

运行时类:自从

    List<String> ls = new ArrayList<String>();
    Class<? extends List> c1 = ls.getClass();
    Class<List> c2 = List.class;
Run Code Online (Sandbox Code Playgroud)

编译但是

    Class<? extends List<?>> c3 = ls.getClass();
    Class<List<?>> c4 = List.class;
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:为什么它不编译

从评论中解脱出来:

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

List.class是类型的Class<List>.由于List<?>List是不同的类型,Class<List<?>>并且Class<List>是不相关的类型,但是赋值的右手类型必须是左手类型的子类型.的getClass()情况下是类似的.

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

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

(来源)

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

(来源)

我们写|T|的是类型的擦除T.

(来源)

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

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

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

  • @irreputable - "我确实质疑规范".好吧那太糟糕了.因为Java语言**是以这种方式指定的,而这正是Java编译器必须实现的.(如果Java设计人员在大约2000年获得了"干净的名单",他们就不会像这样设计Java泛型.但是没有:出于兼容性原因,他们不得不采用"类型擦除"方法.) (2认同)

Kal*_*Kal 5

Class<? extends List<?>>
Run Code Online (Sandbox Code Playgroud)

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