简体   繁体   中英

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

I found this apparently odd behaviour in method-overriding/overloading of Java, that has been boggling my mind. The call in the Main() method prints out " B_A ", while I would expect it to be " 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        
    } 
}

I break down the process as the following:

  1. The compiler selects method method() of class B
  2. During runtime, JVM calls method method() of its superclass via super()
  3. 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. <- this statement is wrong (thanks Alexey Romanov and pvg). Selection of methods, overloading-wise, is always done at compile time. That is, that method translates to .m(A) before runtime. At runtime, the proper overriding method is chosen.
  4. Why is the method method(A a) of class B being invoked, instead?

My guess is that the JVM, when it selects a subclass method during runtime, starts looking up into a table of overloaded methods, where is a fixed precedence and the methods with a arguments of higher classes in the hierarchy are looked up first. That is, it doesn't go straight for B.method(B b) , instead it looks it up into such a table and it's ok with the first compatible method - B.method(A a) - as B is A.

Another idea is that the call this.method(this) in class A calls B.method(A a) straight out, but that would imply that the same symbol ( this ) in the same context could refer to different objects.

Any help sorting this out? Thanks in advance!

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.

This step is wrong. Note that overloaded methods (that is, multiple methods with same name) are resolved by the compiler. In class A , this has type A , so this.method(this) calls method(A a) . Then at runtime B 's implementation of that method is used.

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

No, it calls just method(A a) . It doesn't know anything about B .

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

It wouldn't and doesn't imply that.

I'll also note that public void method(){ super.method(); } public void method(){ super.method(); } in B doesn't affect anything in this question.

In addition to the above discussed answers,

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

Irrespective of the reference type in the first and second case, the objects are for class B .
The method() call for bb and ab invokes the super.method() block.
This calls the method() from A class and passes reference of its own class to this.method(this) ie this.method(A);
This invokes the method method(A a) under B at run-time (method overridding).

In the third case, this.method(this) invokes the method method(A a) under class A.
This happens at the compile time itself (method overloading)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM