我也觉得这个问题很难理解;将单个命令分成两个命令对我有帮助。
下面的代码是在检查和编译原始方法时在后台实际发生的情况,编译器生成自己的局部变量:i.get(0)
调用的结果放在局部变量堆栈上的寄存器中。
那就是——为了理解这个问题——与制作一个局部变量相同,为方便起见,我给出了这个名称element
。
import java.util.List;
public class WildcardError {
void foo(List<?> i) {
Object element = i.get(0); // command 1
i.set(0, element); // command 2
}
}
检查命令 1 时,它只能将类型设置element
为Object
(--> 上限概念,参见马特的回答),因为它不能?
用作变量类型;仅用于?
指示泛型类型未知。
变量类型只能是真实类型或泛型类型,但由于您在此方法中不使用泛型类型,<T>
例如,它被迫使用真实类型。由于 java 规范 (jls8, 18.2.1) 中的以下行,执行此强制:
‹Expression → T›形式的约束公式简化如下:
[...]
— 如果表达式是类实例创建表达式或方法调用表达式,则约束减少到绑定集 B3,当以 T 为目标时,约束集将用于确定表达式的调用类型,如第 18.5.2 节中定义的那样。(对于类实例创建表达式,用于推理的相应“方法”在 §15.9.3 中定义)。