Java如何处理可能不明确的方法调用?
在使用具有多个参数的模糊方法调用时,我注意到,在我预期的情况下,它通常实际上并不模糊,这导致了一些我无法完全理解的奇怪行为 例如,使用以下继承结构:Java如何处理可能不明确的方法调用?,java,inheritance,ambiguous,Java,Inheritance,Ambiguous,在使用具有多个参数的模糊方法调用时,我注意到,在我预期的情况下,它通常实际上并不模糊,这导致了一些我无法完全理解的奇怪行为 例如,使用以下继承结构: public static class A { } public static class B extends A { } public static class C extends B { } 并运行方法test() 出于某种原因,这两种方法是不明确的 public static void test(A x, A xx, B xxx) {
public static class A {
}
public static class B extends A {
}
public static class C extends B {
}
并运行方法test()
出于某种原因,这两种方法是不明确的
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中如何使用多个参数准确地确定准不明确的方法调用吗
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所指出的,语言规范是这里的权威,但我也喜欢实验。这是因为两种测试方法都可以接受
C
的实例作为其参数,因为C
可以充当B
和A
阅读Java语言规范一章,以下陈述值得注意:
一种适用方法m1比另一种适用方法更具体
方法m2,对于参数表达式e1,…,ek的调用,
如果
…m2不是通用的,m1和m2通过严格的或
松散调用,其中m1具有形式参数类型S1,…,Sn
m2有形式参数类型T1,…,Tn,类型Si更多
所有i(1)的参数ei比Ti具体≤ 我≤ n、 n=k)
这基本上意味着,给定两个(非varargs)可以匹配一个方法调用的方法签名,编译器将选择更具体的方法,而更具体的方法是其中每个参数比另一个签名中的相应参数更具体(即与另一个签名中的相应参数相同的类或其子类)(为了简单起见,这里忽略泛型)
例如,当你有(A,A,B)和(A,A,C)时,后者更具体,因为A=A,C是B的一个子类,所以选择是明确的
但是当你有(A,A,B)和(A,C,A)时,前者不能更具体,因为C是A的一个子类,而后者也不能更具体,因为B是A的一个子类。因此,模糊性。我试着向你解释问题所在 例如,我有一个类,它包含三个具有不同参数的方法来计算两个数的乘法 这些方法是:
- 长mul(整数x,长y)
- 长mul(长x,内y)
- 长mul(长x,长y)
int x;
long y;
- 如果我调用mul(x,y),那么我将得到x*y,因为mul(int,long)是最长的 这些参数的具体方法
- 如果我调用mul((long)x,y),那么我将再次得到x*y,因为mul(long,long)是这些参数最具体的方法
- 相反,如果我调用mul(x,x),我不会得到x*x,因为语言(Java)无法猜测参数的最佳转换是什么
我希望我能帮助你!我只想指出,你所描述的不是“多重继承”,而是一系列单一继承。@bhspencer我的错,我删除了标记,我几乎可以肯定这是重复的。只需查看方法重写的规则。这由Java语言规范的规则决定().它们又长又复杂。没有人知道它们的全部。但这不是问题,因为没有人使用这种含糊不清的重载,因为它们很难正确。
int x;
long y;