我有以下不能编译的代码,虽然有一种方法可以使它编译,我想了解它为什么不编译。有人可以告诉我具体为什么我会收到我将在最后发布的错误消息吗?
public class Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(null);
}
public <T extends Test> void testT(Class<T> type) {
Class<T> testType = type == null ? Test.class : type; //Error here
System.out.println(testType);
}
}
Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>
通过将Test.class
投射到Class<T>
,可以使用Unchecked cast
警告进行编译并完美运行。
答案 0 :(得分:23)
原因是Test.class属于Class&lt; Test&gt;类型。您不能分配Class&lt; Test&gt;类型的引用到类&lt; T&gt;类型的变量因为它们不是一回事。然而,这有效:
Class<? extends Test> testType = type == null ? Test.class : type;
通配符允许Class&lt; T&gt;和类&lt;测试&gt;引用分配给testType。
Angelika Langer Java Generics FAQ有大量有关Java泛型行为的信息。我将根据那些使用Number
类heirarchy 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
的子类,因此这在任何情况下都是完全合法且可能有用。
答案 1 :(得分:4)
假设我扩展了测试:
public class SubTest extends Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(new SubTest());
}
}
现在,当我调用testT
时,类型参数<T>
为SubTest
,这意味着变量testType
为Class<SubTest>
。 Test.class
类型为Class<Test>
,不能分配给Class<SubTest>
类型的变量。
将变量testType
声明为Class<? extends Test>
是正确的解决方案;施放到Class<T>
隐藏着一个真正的问题。
答案 2 :(得分:1)
删除条件,错误更好......
public class Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(null);
}
public <T extends Test> void testT(Class<T> type) {
Class<T> testClass = Test.class;
System.out.println(testClass);
}
}
Test.java:10: incompatible types
found : java.lang.Class<Test>
required: java.lang.Class<T>
Class<T> testClass = Test.class;