从超类构造函数调用基类重写方法

时间:2015-10-19 13:16:36

标签: java inheritance

鉴于以下代码块我想了解为什么以及如何强调如何,调用Subclass中的方法print:

class Super {

    Super() {

        // what happens so that Sub's method print() is invoked
        print();
    }

    public void print() {

        System.out.println("in super");
    }
}

class Sub extends Super {

    Sub() {

        super();
    }

    public void print() {

        System.out.println("in sub");
    }
}

public class TestClass {

    public static void main(String[] args) {


        Super s = new Sub(); // "in sub".. not so much expected

        s.print(); // "in sub".. as expected
    }
}

我的理解是,在编译期间,类将获得与属于某个类的方法相关联的V表指针vtblPtr。 因此,类Super应该引用它自己的方法print()的实现。

为什么在print()的构造函数中调用Sub中的方法Super?这里到底发生了什么?

2 个答案:

答案 0 :(得分:3)

以下是JVM的Super类(实际上,这是javap -c Super获得的人类可读版本)

class Super {
  Super();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0       
       5: invokevirtual #2                  // Method print:()V
       8: return        

  public void print();
    Code:
       0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #4                  // String in super
       5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return        
}

如您所见,print内部Super构造函数在编译时未解析为Super::print。虚拟调用意味着它在运行时针对this类进行解析。

答案 1 :(得分:2)

  

我的理解是,在编译期间,类将获得V-table pointervtblPtrassociated与方法'属于'类。因此,Class Super应该参考它自己的方法print()的实现。

您对虚拟方法和覆盖有一个基本的误解。在Java中,每个非static,非 - private方法都是虚拟的。从任何地方对虚拟方法进行的每次虚拟(正常)调用都将调用与调用该方法的对象的类关联的版本。该版本可能会或可能不会被继承,并且可能会或可能不会覆盖超类的方法。

虚拟方法调用在this上隐式或显式执行,绝不会改变任何方式。特别是,正在初始化的对象的实际类对于每个构造函数都是可见的,并为其所有方法调用提供上下文。实际上,这就是构造函数调用由自己的类提供的虚方法的好主意。超类构造函数在子类构造函数之前运行,因此如果超类构造函数调用碰巧被子类覆盖的方法,那么该方法将在对象以该方法可能采用的方式完全初始化之前运行。