为什么使用Collection <string> .class非法?</string>

时间:2010-04-30 14:31:18

标签: java

我对仿制药感到困惑。您可以声明如下字段:

Class<Collection<String>> clazz = ...

您可以将此字段指定为:

,这似乎是合乎逻辑的
Class<Collection<String>> clazz = Collection<String>.class;

但是,这会产生错误:

  

令牌“&gt;”上的语法错误,此令牌后面的空格

所以看起来.class运算符不适用于泛型。所以我试过了:

  class A<S> { }
  class B extends A<String> { }
  Class<A<String>> c = B.class;

也不起作用,生成:

  

类型不匹配:无法转换为Class<Test.StringCollection> to Class<Collection<String>>

现在,我真的不明白为什么这不起作用。我知道泛型类型没有具体化,但在这两种情况下,它似乎完全是类型安全的,无需访问运行时泛型类型。有人有想法吗?

3 个答案:

答案 0 :(得分:30)

泛型是不变的。

Object o = "someString"; // FINE!
Class<Object> klazz = String.class; // DOESN'T COMPILE!
// cannot convert from Class<String> to Class<Object>

根据您的需要,您可以使用通配符。

Class<? extends Number> klazz = Integer.class; // FINE!

或许你需要这样的东西:

Class<List<String>> klazz =
   (Class<List<String>>) new ArrayList<String>().getClass();
// WARNING! Type safety: Unchecked cast from
//   Class<capture#1-of ? extends ArrayList> to Class<List<String>>

对于非运行时的情况,你似乎掌握得很好,但无论如何,这是一个引用,来自Java Tutorials on GenericsThe Fine Print一个通用类是所有调用共享

  

以下代码片段打印的内容是什么?

List <String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
     

你可能想说false,但你错了。它打印true,因为泛型类的所有实例都具有相同的运行时类,而不管它们的实际类型参数如何。

也就是说,没有List<String>.classList<Integer>.class这样的东西;只有List.class

这也反映在JLS 15.8.2 Class Literals

  

类文字是一个表达式,由类,接口,数组或基本类型的名称或伪类型void组成,后跟.和标记class。< / p>

请注意省略泛型类型参数/参数的任何限制。此外,

  

如果发生以下任何情况,则为编译时错误:

     
      
  • 命名类型是类型变量或参数化类型,或者是元素类型为类型变量或参数化类型的数组。
  •   

也就是说,这也不能编译:

void <T> test() {
    Class<?> klazz = T.class; // DOESN'T COMPILE!
    // Illegal class literal for the type parameter T
}

基本上你不能将泛型与类文字一起使用,因为它没有意义:它们是未定义的。

答案 1 :(得分:1)

我同意其他答案,并想进一步解释一点:

类对象表示加载到JVM内存中的类。每个类对象实际上是.class文件的内存中实例。 Java泛型是单独的类。它们只是编译时类型检查机制的一部分。因此,它们在类对象中没有运行时表示。

答案 2 :(得分:0)

Java中的类文字似乎缺乏,没有办法用通用信息创建类文字,而这在某些情况下很有用。因此,无法调用以下代码,因为无法提供类文字

class A<S> {}
<S> A<S> foo( Class<A<S>> clazz ) {}
A<String> a = foo( A<String>.class ) // error

然而,我的主要问题是我也不能用扩展A的B类调用它。这是由不变性限制引起的。这是通过使用通配符解决的:

class A<S> {}
class B extends A<String> {}     
<S> A<S> foo( Class<? extends A<S>> clazz ) { return null; }
void test () {
    A<String> s = foo( B.class ); 
}

那说我没有找到原因导致Class<A<S>>.class无效的根本原因。擦除或边界似乎都不要求这是无效的。