泛型中的通配符
?
表示未知类型并且仅接受null
。 但是,在下面的示例中,构造函数接受 (例如) 一个
String
对象,即使我已经声明了
Test<?>
的实例。
public class Test<T> {
private T object;
public Test(T object) {
this.object = object;
}
public void set(T object) {
this.object = object;
}
public static void main(String[] args) {
Test<?> test = new Test<>("Test"); // compiles fine
//test.set("Test"); // compiler error
}
}
为什么可以正常编译?
构造函数接受(例如)一个不。您已声明了类型为
String
对象,即使我已经声明了Test<?>
的实例。
Test<?>
的 variable
。您已经创建了一个类型为
Test<X>
的 实例,对于某些
X
,编译器有义务自行计算出来,以便整个语句有效。也就是说,这里:
Test<?> test = new Test<>("Test"); // compiles fine
... <>
并不意味着“从变量的类型复制类型参数”或类似的东西。
Test<?>
不是表达式
new Test<>("Test")
的类型。所选类型参数必须使类型可分配给类型
Test<?>
是必须满足的约束之一,但这很简单,因为任何
X
都可以做到这一点。正式地,Java 将推断出满足语句有效的所有约束的最具体类型参数。
new Test<X>("Test")
仅对相对较少的
X
有效:
java.lang.Object
java.lang.Serializable
java.lang.Comparable<String>
以及
Comparable
的一些其他变体
java.lang.CharSequence
java.lang.constant.Constable
(自 Java 12 起)
java.lang.constant.ConstantDesc
(自 Java 12 起)
java.lang.String
String
其中最具体,因此选择它。然而,在实践中,Java 实际上根本不需要选择特定的类型参数。它只需让自己满意,至少有一个有效。
test.set("Test")
是另一种情况。分配给
test
的对象被推断为类型
Test<String>
并不重要。在这里,与在所有情况下一样,java 根据所涉及的任何变量的“声明”类型来分析表达式。
test
使用类型 Test<?>
进行声明。因此,Java 无法确信
test.set()
会接受任何类型作为参数。但是,值
null
与每种引用类型兼容,因此无论对象
test
引用的特定类型参数是什么,
null
都是
test.set()
可接受的参数。