JVM

深入理解Java虚拟机总结-对象的创建过程

Posted by AlstonWilliams on February 17, 2019

今天同学问我下面的代码,输出结果为什么会是那样.查阅资料之后,终于给了她答案,我也对Java中对象的创建过程有了更深的理解.

有两个问题:

  • 为什么调用Parent的构造器时,里面调用的printName()方法却是Child的?
  • 为什么调用Parent的构造器时,printName()方法输出的是null?

我们先介绍一下对象的创建过程:

  • 查看对应的类是否被加载过,如果没有被加载过,那么就先执行对应类的加载过程
  • 为对象分配内存空间
  • 将此内存空间初始化为零值
  • 执行invokespecial来调用类的构造函数
    • 先调用父类的构造函数
    • 对类的实例变量赋初值
    • 继续执行类的构造函数

我们拿上面的例子来解释一下这个过程:

  • 首先,加载类Child,在连接阶段,发现还有父类没有被加载,就去加载父类Parent
  • 为Child类的对象分配内存空间
  • 将Child类对象的内存空间初始化为零值
  • 调用Child类对象的构造函数
    • 先通过super()调用父类的构造函数
    • 再对Child类对象的name实例变量进行初始化,初始化为”child”
    • 调用Child类实例构造器中剩下的语句,即printName()

我们先解释为什么调用Parent的构造函数时,其中调用的printName()方法是调用的Child的printName()方法.

在调用Parent的构造方法时,当调用printName()方法时,实际上调用的是this.printName(),而此时this是啥呢?是上面我们提到的那个Child类的对象.从Child的类的字节码中我们就能看到:

那么为什么第一行输出的name是null呢?

从上面的过程中,我们可以看到,由于是先调用父类的构造函数,随后对Child类对象的name实例变量进行初始化,所以上面输出的是null.