我试图了解Java如何处理函数调用中的歧义。在下面的代码中,对method
的调用是不明确的,但对method2
的调用不是!
我觉得两者都模棱两可,但是当我注释掉对method
的调用时为什么会编译呢?为什么method2
也没有歧义?
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进行编译。
最佳答案
测试method1
是否比method2
更具体的一种直观方法是查看是否可以通过使用相同参数调用method1
来实现method2
。
method1(params1){
method2(params1); // if compiles, method1 is more specific than method2
}
如果存在变量,则可能需要扩展变量,以便2个方法具有相同数量的参数。
让我们检查示例中的前两个
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
}
(返回类型不用于确定特异性,因此将其省略)
两者都编译,因此每个都比另一个更具体,因此含糊不清。您的
method2()
也是如此,它们比彼此更具体。因此,对method2()
的调用是模棱两可的,不应编译。否则是编译器错误。这就是规范所说的;但这合适吗?当然,
method_a
看起来比method_b
更具体。实际上,如果我们使用具体类型而不是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_a
比method_b
更具体,反之亦然。差异源自类型推断的魔力。
L1
/L2
调用没有显式类型实参的泛型方法,因此编译器尝试推断类型实参。类型推断算法的目标是找到类型参数,以便代码进行编译!难怪L1和L2会编译。 L2实际上推断为this.<Object>method_a(arg, otherArgs)
类型推断试图猜测程序员想要什么,但是有时候猜测肯定是错误的。我们的真正意图是
<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
}
关于java - 具有泛型和varargs的歧义重载Java方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/10642241/