为什么 Test<?> 的实例在构造函数中接受非空对象?

问题描述 投票:0回答:1

泛型中的通配符

?表示未知类型并且仅接受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 } }
为什么可以正常编译?

java generics wildcard
1个回答
0
投票
构造函数接受(例如)一个

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()
 可接受的参数。

© www.soinside.com 2019 - 2024. All rights reserved.