generics类型推断失败了吗?

例A

研究以下片段:

public class ExampleA { static class Pair { } static  Pair anyPair() { return null; } static  void process(Pair p1, Pair p2) { return; } public static void main(String[] args) { Pair p = anyPair(); process(p, anyPair()); // doesn't compile } } 

有人可以解释为什么类型推断适用于局部变量p的赋值但不适用于要process的第二个实际参数吗?


例B

这可能更容易理解:

 public class ExampleB { public static  void process(Set s1, Set s2) { return; } public static void main(String[] args) { process(new HashSet(), Collections.emptySet()); // doesn't compile } } 

同样的问题:为什么不编译?

我希望Collections.emptySet()只适用于任何参数化的Set类型。

您对anyPair()第二次调用没有任何方法来确定它的类型,因此它默认为

编译器正在破坏process(p, anyPair()); 把它分成几块并单独处理。 当它这样做时,它需要首先处理参数以确定它们的类型,然后可以在处理process时使用它们。

当它去处理anyPair() ,没有可用于该片段的类型信息,因为它不知道它是该点的process一部分。 它默认为 ,这会在查看process时导致类型不匹配。

你的第二个例子也发生了同样的事情。 Collections.emptySet()需要自己处理,但无法确定所需的类型。

有两种方法可以解决这个问题:

第一种方法是为编译器提供类型推断所需的信息,方法与第一次调用anyPair() ,方法是将其存储在具有正确类型的临时变量中。

第二个(感谢@BalusC)是使用ExampleA.anyPair() 。 此语法显式设置所需的类型,而不必超出调用范围。

为什么:

Collections.emptySet()试图推断要返回的类型。 它不能,因为E可能是ObjectString 。 两者都是进程的有效匹配。 默认情况下,通用参数始终不变,而不是逆变。 这意味着Integer extends NumberList 没有扩展List 。 它确实扩展了List 但是, List

解决方案:

使用赋值来推断类型:

 public  void process(Set s1, Set s2) { return; } public void main(String[] args) { Set s = Collections.emptySet(); // add this line process(new HashSet(), s); } 

明确写出类型:

 public  void process(Set s1, Set s2) { return; } public void main(String[] args) { process(new HashSet(), Collections.emptySet()); //notice  } 

明确允许逆转(但这可能不是你想要的):

 public  void process(Set s1, Set s2) { // added "super" return; } public void main(String[] args) { process(new HashSet(), Collections.emptySet()); }