使用子类中的“super”和超类

时间:2017-05-19 14:02:57

标签: java jvm this super overloading

我在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        
    } 
}

我按照以下方式分解了这个过程:

  1. 编译器选择B类
  2. 的方法method()
  3. 在运行时,JVM通过method()
  4. 调用其超类的方法super()
  5. this.method(this)从A类中调用,但this引用B类的实例,因此转换为B类的方法method(B b)&lt ; - 这句话是错误的(感谢Alexey Romanov和pvg)。方法的选择,即重载方式,总是在编译时完成。也就是说,该方法在运行时转换为.m(A)。在运行时,选择适当的重写方法。
  6. 为什么要调用B类的方法method(A a),而不是?
  7. 我的猜测是,JVM在运行时选择子类方法时,会开始查找重载方法的表,其中是一个固定的优先级,并且首先查找层次结构中具有更高类的参数的方法。也就是说,它不会直接用于B.method(B b),而是将其查找到这样的表中,并且第一个兼容方法可以正常 - B.method(A a) - 因为B是A.

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

    任何帮助整理出来的?提前谢谢!

2 个答案:

答案 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 Bmethod()bb的{​​{1}}调用会调用ab块。
这会从super.method()调用method()并将其自己的类的引用传递给A class,即this.method(this) 这将在运行时调用B下的方法this.method(A);(方法重写)。

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