类泛型的类型不匹配 [英] Type mismatch for Class Generics
问题描述
我有下面的代码不能编译,虽然有一种方法可以编译,但我想知道它为什么不编译。有人能够启发我,特别是为什么我会在最后发布错误消息吗?
public class Test {
public static void main(String args []){
Test t = new Test();
t.testT(null);
}
public< T扩展测试> void testT(Class< T> type){
Class< T> testType = type == null? Test.class:type; //错误在这里
System.out.println(testType);
code $
$ b $类型不匹配:不能转换从Class
通过将 Test.class
转换为 Class< T>
这个编译时带有一个未经检查的转换
警告,并且完美运行。 原因是Test.class是Class< Test>类型的。您无法指定类型为Class< Test>的类型的引用到类型< T>的变量,因为它们不是一回事。然而,这是有效的:
Class <?扩展测试> testType = type == null? Test.class:type;
通配符允许Class< T>和Class< Test>引用将被分配给testType。
有关Java泛型行为的大量信息在 Angelika Langer Java泛型常见问题解答。我将根据那些使用 Number
class heirarchy Java的核心API的一些信息提供示例。
请考虑以下方法:
public< T extends Number> void testNumber(final Class< T> type)
这是为了让下列语句成功编译:
testNumber(Integer.class);
testNumber(Number.class);
但以下内容无法编译:
testNumber(String.class);
现在考虑以下语句:
类<号> numberClass = Number.class;
Class< Integer> integerClass = numberClass;
第二行无法编译并产生此错误类型不匹配:无法转换来自Class< Number>到Class< Integer>
。但是 Integer
扩展 Number
,那为什么会失败呢?看看下面两条语句,看看为什么:
Number anumber = new Long(0);
整数another = anumber;
很容易明白为什么第二行不能在这里编译。您无法将 Number
的实例分配给 Integer
类型的变量,因为无法保证 Number
实例是兼容类型。在这个例子中, Number
实际上是一个 Long
,它当然不能被分配给整数
。实际上,错误也是类型不匹配:类型不匹配:无法从数字转换为整数
。
规则是一个实例不能被分配给一个变量,该变量是实例类型的子类,因为不能保证它是兼容的。
泛型行为在类似的方式。在通用方法签名中, T
只是一个占位符,用于指示该方法允许编译器使用的方法。当编译器遇到 testNumber(Integer.class)
时,它实质上用 Integer替换 T
code>。
通配符增加了额外的灵活性,如下所示:
类< ;?扩展Number> wildcard = numberClass;
由于 Class <? extends Number>
表示任何类型,它是 Number
或者是 Number
的子类,这是完全合法并且在许多情况下可能有用。
I have the following code that won't compile and although there is a way to make it compile I want to understand why it isn't compiling. Can someone enlighten me as to specifically why I get the error message I will post at the end please?
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>
By casting Test.class
to Class<T>
this compiles with an Unchecked cast
warning and runs perfectly.
解决方案 The reason is that Test.class is of the type Class<Test>. You cannot assign a reference of type Class<Test> to a variable of type Class<T> as they are not the same thing. This, however, works:
Class<? extends Test> testType = type == null ? Test.class : type;
The wildcard allows both Class<T> and Class<Test> references to be assigned to testType.
There is a ton of information about Java generics behavior at Angelika Langer Java Generics FAQ. I'll provide an example based on some of the information there that uses the Number
class heirarchy Java's core API.
Consider the following method:
public <T extends Number> void testNumber(final Class<T> type)
This is to allow for the following statements to be successfully compile:
testNumber(Integer.class);
testNumber(Number.class);
But the following won't compile:
testNumber(String.class);
Now consider these statements:
Class<Number> numberClass = Number.class;
Class<Integer> integerClass = numberClass;
The second line fails to compile and produces this error Type mismatch: cannot convert from Class<Number> to Class<Integer>
. But Integer
extends Number
, so why does it fail? Look at these next two statements to see why:
Number anumber = new Long(0);
Integer another = anumber;
It is pretty easy to see why the 2nd line doesn't compile here. You can't assign an instance of Number
to a variable of type Integer
because there is no way to guarantee that the Number
instance is of a compatible type. In this example the Number
is actually a Long
, which certainly can't be assigned to an Integer
. In fact, the error is also a type mismatch: Type mismatch: cannot convert from Number to Integer
.
The rule is that an instance cannot be assigned to a variable that is a subclass of the type of the instance as there is no guarantee that is is compatible.
Generics behave in a similar manner. In the generic method signature, T
is just a placeholder to indicate what the method allows to the compiler. When the compiler encounters testNumber(Integer.class)
it essentially replaces T
with Integer
.
Wildcards add additional flexibility, as the following will compile:
Class<? extends Number> wildcard = numberClass;
Since Class<? extends Number>
indicates any type that is a Number
or a subclass of Number
this is perfectly legal and potentially useful in many circumstances.
这篇关于类泛型的类型不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!