含generics和可变参数的模糊重载java方法

我想了解Java如何处理函数调用中的歧义。 在下面的代码中,对method的调用是不明确的,但method不是。

我觉得两者都是模棱两可的,但是为什么当我注释掉method的调用时,这会编译? 为什么方法2也不明确?

 public class A { public static <K> List<K> method(final K arg, final Object... otherArgs) { System.out.println("I'm in one"); return new ArrayList<K>(); } public static <K> List<K> method(final Object... otherArgs) { System.out.println("I'm in two"); return new ArrayList<K>(); } public static <K, V> Map<K, V> method2(final K k0, final V v0, final Object... keysAndValues) { System.out.println("I'm in one"); return new HashMap<K,V> (); } public static <K, V> Map<K, V> method2(final Object... keysAndValues) { System.out.println("I'm in two"); return new HashMap<K,V>(); } public static void main(String[] args) { Map<String, Integer> c = A.method2( "ACD", new Integer(4), "DFAD" ); //List<Integer> d = A.method(1, "2", 3 ); } } 

编辑:这在评论中提到:许多IDE报告都是模棱两可的 – IntelliJ和Netbeans到目前为止。 不过,它从命令行/ maven编译得很好。

testingmethod1是否比method2更具体的一个直观的方法是通过调用具有相同参数的method2来查看method1是否可以实现

 method1(params1){ method2(params1); // if compiles, method1 is more specific than method2 } 

如果有可变参数,我们可能需要扩展一个可变参数,以使两个参数具有相同的参数个数。

让我们来看看你的例子中的前两个method()

 <K> void method_a(K arg, Object... otherArgs) { method_b(arg, otherArgs); //ok L1 } <K> void method_b(Object arg, Object... otherArgs) { // extract 1 arg from vararg method_a(arg, otherArgs); //ok L2 } 

(返回types不用于确定特异性,所以省略)

两者都编译,因此每一个都比另一个更具体,因此含糊不清。 你的method2()同样适用,它们比对方更具体。 因此,调用method2()是不明确的,不应该编译; 否则这是一个编译器错误。


所以这就是规范所说的。 但它是正确的? 当然, method_a看起来比method_b更具体。 其实如果我们有一个具体的types,而不是K

 void method_a(Integer arg, Object... otherArgs) { method_b(arg, otherArgs); // ok } void method_b(Object arg, Object... otherArgs) { method_a(arg, otherArgs); // error } 

那么只有method_amethod_b更具体,反之亦然。

types推断的魔力产生了差异。 L1 / L2调用不带显式types参数的generics方法,因此编译器试图推断types参数。 types推理algorithm的目标是find代码编译的types参数! 难怪L1和L2编译。 L2实际上是推断this.<Object>method_a(arg, otherArgs)

types推断试图猜测程序员想要什么,但有时猜测肯定是错的。 其实我们真正的意图是

 <K> void method_a(K arg, Object... otherArgs) { this.<K>method_b(arg, otherArgs); // ok } <K> void method_b(Object arg, Object... otherArgs) { this.<K>method_a(arg, otherArgs); // error }