今天同学问我下面的代码,输出结果为什么会是那样.查阅资料之后,终于给了她答案,我也对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.