Java 运行时方法选择在子 class 中使用 "super" 并在超级 class 中使用 "this"

Java runtime method selection using "super" in the subclass and "this" in the super class

我在 Java 的 method-overriding/overloading 中发现了这种明显奇怪的行为,这一直困扰着我。 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        
    } 
}

我把这个过程分解如下:

  1. 编译器选择方法method() of class B
  2. 在运行时,JVM 通过 super()
  3. 调用它的 superclass 的方法 method()
  4. this.method(this) 从 class A 中调用,但 this 引用 class B 的实例,因此转换为方法 method(B b) of class B. <- 这个说法是错误的(感谢 Alexey Romanov 和 pvg)。方法的选择,重载方面,总是在编译时完成。也就是说,该方法在运行时之前转换为 .m(A) 。在运行时,选择正确的覆盖方法。
  5. 为什么调用的是 class B 的方法 method(A a)

我的猜测是,当 JVM 在运行时选择一个 subclass 方法时,它开始查找 table 重载方法,其中 是固定优先级和具有首先查找层次结构中较高 classes 的参数。也就是说,它不会直接找到 B.method(B b),而是查找 table 并且第一个兼容方法没问题 - B.method(A a) - 因为 B 是 A。

另一个想法是 class A 中的调用 this.method(this) 直接调用 B.method(A a),但这意味着相同的符号 (this) 在相同的上下文中可以引用不同的对象。

有人帮忙解决这个问题吗?提前致谢!

this.method(this) gets called from within class A, but this refers to an instance of class B, therefore translating to method method(B b) of class B.

这一步错了。请注意,重载 方法(即具有相同名称的多个方法)由编译器解析。在 class A 中,this 具有类型 A,因此 this.method(this) 调用 method(A a)。然后在运行时 B 的实现使用 方法。

Another idea is that the call this.method(this) in class A calls B.method(A a) straight out,

不,它只调用 method(A a)。它对 B.

一无所知

but that would imply that the same symbol (this) in the same context could refer to different objects.

不会也不暗示。

我还会注意到 B 中的 public void method(){ super.method(); } 不会影响此问题的任何内容。

除了上面讨论的答案,

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() 调用 bbab 调用 super.method() 块。
这从 A class 调用 method() 并将它自己的 class 的引用传递给 this.method(this)this.method(A);
这会在 运行 时间调用 B 下的方法 method(A a)(方法覆盖)。

第三种情况,this.method(this)调用了classA下的方法method(A a)
这发生在编译时本身(方法重载)