Java 为什么要使用集合<;字符串>;。上课不合法?

Java 为什么要使用集合<;字符串>;。上课不合法?,java,Java,我对泛型感到困惑。您可以声明如下字段: Class<Collection<String>> clazz = ... 也不起作用,生成: 类型不匹配:无法从类转换为类 现在,我真的不明白为什么这不起作用。我知道泛型类型没有具体化,但在这两种情况下,它似乎是完全类型安全的,而不需要访问运行时泛型类型。有人有想法吗?泛型是不变的 Object o = "someString"; // FINE! Class<Object> klazz = St

我对泛型感到困惑。您可以声明如下字段:

Class<Collection<String>> clazz = ...
也不起作用,生成:

类型不匹配:无法从
类转换为类


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

泛型是不变的

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

基本上,您不能将泛型与类文本一起使用,因为这毫无意义:它们是非具体化的。

Java中似乎缺少类文本,无法使用泛型信息创建类文本,而这在某些情况下很有用。因此,无法调用以下代码,因为无法提供类文本

class A<S> {}
<S> A<S> foo( Class<A<S>> clazz ) {}
A<String> a = foo( A<String>.class ) // error
class A{}
一个foo(类clazz){}
A=foo(A.class)//错误
然而,我的主要问题是,我也不能用扩展了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{}
类B扩展了{}

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


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

请看,我想我理解方差及其陷阱,但我看不出这与这里的情况有关。注意,像:Class s;这样的字段是完全合法的。由于神秘的原因,赋值失败。实际上,不变性是一个技巧:Class@Peter:类文本不是类型。许多泛型类型是不变的,不赋值nt相互兼容,在运行时确实是同一个类的实例。允许类文本使用泛型没有任何意义。@彼得:你说“实际上,不变性是诀窍”——更准确地说,使用(有界)通配符是诀窍。你应该读更多关于如何使用它们的内容,PEC(Producer扩展Consumer Super)原理以及它促进了什么,等等。我仍然不明白为什么不能给类分配一个文本a.Class?而类B扩展了a{}allows ClassGenerics是编译期间的约束,在运行时通常不可用。但是,我不打算让generic type参数在运行时可用。例如,ArrayList.class.newInstance()似乎完全可以接受。我没有找到这个模型失败的地方,我所能想到的所有示例都不需要类型参数的运行时类信息。我正在寻找一个示例,其中类文本将失败,因为它需要运行时信息…有关编译时的完整类型信息,您可以查看镜像API-我现在不记得链接了。我不认为这是关于编译时的类型(在类意义上)信息,这只是关于类型约束,即类型参数。
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>>
List <String> l1 = new ArrayList<String>();
List<Integer> l2 = new ArrayList<Integer>();
System.out.println(l1.getClass() == l2.getClass());
void <T> test() {
    Class<?> klazz = T.class; // DOESN'T COMPILE!
    // Illegal class literal for the type parameter T
}
class A<S> {}
<S> A<S> foo( Class<A<S>> clazz ) {}
A<String> a = foo( A<String>.class ) // error
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 ); 
}