在使用具有多个参数的模棱两可的方法调用时,我注意到通常情况下它实际上并不是模棱两可的,这导致了一些我无法完全理解的奇怪行为。
例如,具有以下继承结构:
public static class A {
}
public static class B extends A {
}
public static class C extends B {
}
并运行方法test()
。
public static void test() {
test(new C(), new C(), new C());
}
由于某种原因,这两种方法不明确
public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, C xx, A xxx) {
System.out.println("TEST 2");
}
但是在第二种方法中交换最后两个参数会使该参数具有优先权。
public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, A xx, C xxx) {
System.out.println("TEST 2"); //No longer ambiguous, this one is called
}
有人可以解释这种现象吗?一般来说,确切地说,如何在Java中使用多个参数确定准模棱两可的方法调用?
答案 0 :(得分:3)
通读choosing the most specific method上的Java语言规范一章,需要注意以下声明:
一种适用的方法m1比另一种适用的方法更具体 方法m2,用于使用参数表达式e1,...,ek, 如果...
... m2不是通用的,并且m1和m2适用于严格或 松散调用,其中m1具有形式参数类型S1,...,Sn 并且m2具有形式参数类型T1,...,Tn,类型Si更 对于所有i(1≤i≤n,n = k)的自变量ei,都比Ti特异。
这基本上意味着给定两个可以匹配方法调用的(非varargs)方法签名,编译器将选择更具体的方法,而更具体的方法是每个参数比(例如)更具体的方法。与其他签名中的相应参数相同或相同的子类(为简单起见,此处忽略泛型)。
因此,例如,当您拥有(A,A,B)和(A,A,C)时,后者更为具体,因为A = A并且C是B的子类,因此选择是明确且明确的
但是当您有(A,A,B)和(A,C,A)时,前者不能更具体,因为C是A的子类,但是后者也不能更具体,因为B是A的子类。因此,模棱两可。
答案 1 :(得分:0)
public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, C xx, A xxx) {
System.out.println("TEST 2");
}
这里的问题是这两种方法都适用于(A, C, B)
。在这种特定情况下,存在歧义。
在您提供的明确示例中,两个声明没有通用的签名:
public static void test(A x, A xx, B xxx) {
System.out.println("TEST 1");
}
public static void test(A x, A xx, C xxx) {
System.out.println("TEST 2"); //No longer ambiguous, this one is called
}
第一个应用于(A, A, B)
,第二个应用于(A, A, C)
。第二个只是在提供更具体的用例(签名)时覆盖了前者。您可能希望将其视为覆盖前者,尽管这可能不是技术术语。
通过扩展名C
是A
,因此,在选择参数为C
或A
的调用方法的情况下,解释器将调用其中之一(因此可能会产生歧义)但必须使用更具体的参数(如果有)调用它。这可以描述为多态性。实例的运行时类型用于确定类,然后从降级的类开始搜索方法调用。
正如JB Nizet所指出的那样,语言规范是这里的权威,但我也想尝试一下。
答案 2 :(得分:0)
这是因为两种测试方法都可以接受C
的实例作为其参数,因为C
可以充当B
和A
答案 3 :(得分:0)
我尝试向您解释问题所在。
例如,我有一个包含三个方法的类,这些方法使用不同的参数来计算两个数字的乘法。
这些方法是:
因为所有这些方法的重载都是有效的,并且计算相同的东西:x和y之间的乘法结果。
假设有两个变量,它们是方法的参数:
int x;
long y;
调用mul(x,x)会导致这个难题:我应该将x强制转换为long,所以调用mul(long,long)或将y强制强制转换为int,因此调用mul(int,int)。
这是在使用重载时会发现的问题。
希望我能帮助您!