目标类型具有通配符时的通用方法类型推断

我知道编译器使用目标类型来确定使generics方法调用适用的类型参数。 例如,在以下声明中:

List listOne = Collections.emptyList(); 

其中Collections.emptyList在其签名中具有类型参数T

 public static final  List emptyList() { 

在这种情况下, T的推断类型参数是String

现在考虑以下内容:

 List listTwo = Collections.emptyList(); 

在这种情况下,推断类型是什么? 是Object吗? 或者它并不重要,因为通配符告诉编译器任何类型都是可能的?

通配符的每种用法都具有与之关联的不同类型。 (通常JLS将此称为“新类型”。)例如,这样的编译器错误如何工作:

 List list0 = ... ; List list1 = ... ; list0.add(list1.get(0)); // error 

因为list0情况下, list0list1由编译器给出了单独的类型

 reference_type_of(List) != reference_type_of(List) 

如果你尝试类似的东西,你可以开始看看它如何适合类型推断

 { List list0 = ... ; List list1 = ... ; test(list0, list1); } static  void test(List list0, List list1) {} 

编译器发出的错误实际上告诉我们它为list0list1生成的类型。

错误:类Ideone中的方法测试不能应用于给定类型;
     test(list0,list1);
     ^
   required:List ,List 
   找到:列出,列出
  原因:没有类型变量T的实例存在
          参数类型List 符合forms参数类型List 
  其中T是一个类型变量:
     T扩展方法 test(List ,List )中声明的Object
   其中CAP#1,CAP#2是新的类型变量: 
      CAP#1扩展了Object的捕获? 
      CAP#2扩展了Object的捕获?

(我的重点是粗体。)这些CAP#...类型是在捕获转换期间生成的。 它向我们展示的是,当检查方法调用表达式时, list0list1被赋予彼此不同的类型。 (对于那些需要对错误进行解释的人:这是因为test声明断言两个列表必须具有相同的T

因此我们现在知道通配符与引用类型相关联,我们可以在类似的情况下看到

 List empty = Collections.emptyList(); 

调用将被推断为类似“上限为Object的新类型”。 或者象征性地我们可以说编译器可能会看到类似的东西

 // target type --> inferred invocation type // vv List empty = Collections.emptyList(); 

虽然:当然我们总是猜测一点,因为它取决于编译器如何实现它。 理论上,对于类似上面的emptyList()简单赋值的emptyList() ,它不必做生成正确字节码的工作。

另外,对不起,我今天感觉不像规格。 本质上,类型推断通过生成一组约束来certificate方法调用应该或不应该编译。 18.5.2中描述的算法以这种方式包含通配符。

在这种情况下,推断类型是什么? 是对象吗? 或者它并不重要,因为通配符告诉编译器任何类型都是可能的?

在一个层面上,这是一个哲学问题,因为类型参数对编译的字节码没有任何影响,所以它具体是什么并不重要。 唯一重要的是,是否不可能满足界限和背景。 只要编译器可以certificate存在某种可以工作的类型,那么在我看来,它应该能够继续编译它而不需要提出实际类型。