原因是Test.class 的类型是Class。您不能将 Class 类型的引用分配给 Class 类型的变量,因为它们不是同一个东西。但是,这有效:
Class<? extends Test> testType = type == null ? Test.class : type;
通配符允许将 Class 和 Class 引用分配给 testType。
Angelika Langer Java Generics FAQ 上有大量关于 Java 泛型行为的信息。我将根据那里的一些信息提供一个示例,该示例使用 Number 类层次结构 Java 的核心 API。
考虑以下方法:
public <T extends Number> void testNumber(final Class<T> type)
这是为了让以下语句能够成功编译:
testNumber(Integer.class);
testNumber(Number.class);
但以下内容无法编译:
testNumber(String.class);
现在考虑这些陈述:
Class<Number> numberClass = Number.class;
Class<Integer> integerClass = numberClass;
第二行编译失败并产生此错误Type mismatch: cannot convert from Class<Number> to Class<Integer>。但是Integer 扩展了Number,那为什么会失败呢?看看下面这两个语句,看看为什么:
Number anumber = new Long(0);
Integer another = anumber;
很容易看出为什么第二行在这里没有编译。您不能将Number 的实例分配给Integer 类型的变量,因为无法保证Number 实例是兼容类型。在此示例中,Number 实际上是 Long,当然不能将其分配给 Integer。其实错误也是类型不匹配:Type mismatch: cannot convert from Number to Integer。
规则是不能将实例分配给作为实例类型的子类的变量,因为不能保证兼容。
泛型的行为方式类似。在泛型方法签名中,T 只是一个占位符,用于指示该方法允许编译器做什么。当编译器遇到testNumber(Integer.class) 时,它实际上将T 替换为Integer。
通配符增加了额外的灵活性,因为以下将编译:
Class<? extends Number> wildcard = numberClass;
由于Class<? extends Number> 表示Number 或Number 的子类的任何类型,因此这是完全合法的,并且在许多情况下都可能有用。