我在Java的方法覆盖/重载中发现了这种显然奇怪的行为,令我难以置信。 Main()
方法中的调用打印出“ B_A ”,而我希望它是“ B_B ”。
package one;
public class A {
public void method(A a){ System.out.println("A_A"); }
public void method(B b) { System.out.println("A_B"); }
public void method(){ this.method(this); }
}
package one;
public class B extends A {
public void method(A a) { System.out.println("B_A"); }
public void method(B b) { System.out.println("B_B"); }
public void method(){ super.method(); }
public static void main(String[] args) {
B bb = new B();
bb.method(); //prints B_A, expected B_B
}
}
我按照以下方式分解了这个过程:
method()
method()
super()
this.method(this)
从A类中调用,但this
引用B类的实例,因此转换为B类的方法method(B b)
。method(A a)
,而不是?我的猜测是,JVM在运行时选择子类方法时,会开始查找重载方法的表,其中是一个固定的优先级,并且首先查找层次结构中具有更高类的参数的方法。也就是说,它不会直接用于B.method(B b)
,而是将其查找到这样的表中,并且第一个兼容方法可以正常 - B.method(A a)
- 因为B是A.
另一个想法是,A类中的调用this.method(this)
直接调用B.method(A a)
,但这意味着同一个上下文中的相同符号(this
) 可以引用不同的对象。
任何帮助整理出来的?提前谢谢!
答案 0 :(得分:4)
this.method(this)从A类中调用,但是这引用了B类的实例,因此转换为B类的方法方法(B b)。
这一步是错误的。请注意,编译器会解析重载方法(即具有相同名称的多个方法)。在课程A
中,this
的类型为A
,因此this.method(this)
会调用method(A a)
。然后在运行时B
执行使用方法。
另一个想法是,在A类中调用this.method(this)直接调用B.method(A a),
不,它只调用method(A a)
。它对B
没有任何了解。
但这意味着相同上下文中的相同符号(this)可以引用不同的对象。
它不会也不会暗示。
我还会注意到public void method(){ super.method(); }
中的B
不会影响此问题中的任何内容。
答案 1 :(得分:1)
除了上面讨论的答案,
B bb = new B();
bb.method(); // ... 1 ... prints B_A
A ab = new B();
ab.method(); // ... 2 ... prints B_A
A aa = new A();
aa.method(); // ... 3 ... prints A_A
无论第一种和第二种情况下的参考类型如何,对象都是class B
对method()
和bb
的{{1}}调用会调用ab
块。
这会从super.method()
调用method()
并将其自己的类的引用传递给A class
,即this.method(this)
这将在运行时调用B下的方法this.method(A);
(方法重写)。
在第三种情况下,method(A a)
调用A类下的方法this.method(this)
这发生在编译时本身(方法重载)