JAVA-初步认识-第九章-继承-子父类中的构造函数-子类的实例化过程-内存图解

Posted 照破山河万朵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JAVA-初步认识-第九章-继承-子父类中的构造函数-子类的实例化过程-内存图解相关的知识,希望对你有一定的参考价值。

一.

现在基于继承,写了一个程序,把对象在内存中创建的过程,初始化的步骤给大家展示一下。

通过具体的实例和打印的方式,来展现它的具体流程。

对于父类,我们是不怎么在乎的,在这里可以将隐式的写出来。

 

(父类上面还有根父类,尤其是在构造函数中)

子类中有一个show()方法,父类中也有一个show(),两者一模一样,这是覆盖。子类中也有自己的super(),和return。

每个方法中都是由return的,但是无返回值,或者无返回值类型的,return可以省略不写。构造函数中貌似一定要有super(); 这是在执行父类的空参数构造函数

如果,我们在创建对象中直接new一个对象,DOS运行后有结果么?有结果,在创建对象,初始化过程中,构造函数里面都有输出语句。

观看上面的截图,只是创建对象,DOS结果为Zi show....0。有输出,但是我以为不会调用到子类的show(),还是说设计覆盖的知识,我理解不够

修改代码后(添加了z对象调用show方法),再次进行输出,DOS显示为两行。

就目前这个结果,这里面我们为了把子类实例化过程当中,涉及到的很少谈论到的细节,给讲述一下。

最后一个类,class ExtendsDemo5的类不画,一个main方法,一个构造器。

我们关注的重点是子父类的变化。

先是主函数进栈,同时加载引用变量z。开始创建子类对象,同时子类继承了父类,而且父类还有继承,继承了根类object。父加载的时候,不会先加载object,它早就存在了。jvm在启动的时候,会加载许多东西,都是对象,没有根类object,这些对象根本不会加载。因此,不用管object类,只要管父类就行。

基于子类继承父类,父类就先进内存了。里面存储父的方法表。(按照截图来看,DOS的结果应该也有输出父类的show方法。)

加载完父类后,紧接着加载子类,子类有super(),指向父类。子类的空间里,也有自己的内容,这样一来子类就加载完毕了。

这时候就要开始new zi对象的建立了,前期要加载很多类到方法区。得先有类,然后才能去创建对象。这时候,就在堆里面了有了子类的对象,分配地址,且里面有一个成员变量num。这个num,初始化是0,这个我们称之为默认初始化。紧接着初始化为8,但是DOS的结果显示为0。这就涉及一个问题,默认初始化和现实初始化到底是什么时候完成的?

现在我们深入地探讨一下,现在子类的构造函数中,添加一输出语句,接着编译运行,DOS的结果如下。

System.out.println("zi cons run")在super();的后面,而父类中的空参数构造函数中调用了show()方法,意味着父类初始化的过程中num有值么?这num没有值,只有默认值。告诉大家是怎么进行初始化的。先对num进行默认初始化,默认完了以后。这个new zi对象就调用了相对应的构造器(即zi()方法,子类中空参数默认函数),这个时候,这个构造器就进栈了,这时,8也还没有呢。

子的构造器就进栈了,且有自己所属,这个子构造一进栈以后,里面有一个super()。这个super就意味着飞到了父类这,它立刻就跟着进栈了,因为有super。

 父类进栈后,也会有this,this值和子类一样,因为大家都默认是同一对象(这块先不解释,因为和多态有点关系)。父一加载完以后,就执行里面的super,指的是object,这就不用再管了。下面父类开始调用父类show(),本来是这样的。运行的时候,当子父类中出现一模一样函数的时候,就会产生覆盖。父类调用的时候,如果里面有this的话,当前的对象是0x0034。

当前对象是什么对象,子类对象。子类对象在运行show()方法的时候,它先在自己区域找,它先找了自己的show()。它就打印了"zi show..."+num(0)。看下面内存中的num,就是0。这里操作结束后,父类构造器出栈。

 

 

弹完栈以后,相当于子类中的super()这句话结束了,但是接着就是System.out.println("zi cons run...."+num),里面又有num了。下面的截图是新的程序。本来子类中没有输出语句的。它先到父类当中进行初始化,父类初始化完毕,才轮到子类的显示初始化(这所有的部分都是在子类构造器加载后开始的,一加载就去了父类中初始化,初始化结束后,又回到子类构造函数中接着搞)。

当年的说法是默认初始化,显示初始化,最后构造函数初始化,那个时候是没有父类,没办法讲super的问题。其实构造器里面有一个分水岭,先执行子类构造器是必须的,但是先要执行子类中的super(),就到了父类了,父类执行完。在执行super()里面的代码之前,再执行子类初始化。可是如果没有父类,做那个演示结果,往往都是显示初始化完,子类在访问过程中有值,好像显示初始化在构造器之后,实际上构造器是先加载,先把父类事忙完,才忙自己的,这是必须的。我们初始化先要把父类忙完,再忙自己的事儿,这个时候num才变成8。再去执行子类中的输出语句的时候,里面的num就已经变成8了。

就在super()后面是个分水岭。在开辟对象空间时,分完地址编号后,成员变量一定要默认初始化,必须有值。默认初始化始终是第一步。

接着子类构造器中一个return,它也弹栈了。

这时候,对象才初始化完毕。这时候,才把0x0034赋值给z,z才指向0x0034对象。

 

接下来,运行z.show()语句的时候,还是到子类中找show方法,num是8。

创建对象不一定在栈中,看下图。(类中也可以书写创建对象语句,从方法区中指挥堆内存,创建对象)

看下面的图,在num=10之前,是从0-8-10,是这么个流程。

 

以上是关于JAVA-初步认识-第九章-继承-子父类中的构造函数-子类的实例化过程-内存图解的主要内容,如果未能解决你的问题,请参考以下文章

JAVA-初步认识-第九章-继承-子父类中的构造函数-子类的实例化过程-内存图解

JAVA-初步认识-第八章-继承-子父类中成员函数特点-覆盖

JAVA-初步认识-第八章-继承-子父类中成员变量的特点

JAVA-初步认识-第九章-抽象类-细节

JAVA-初步认识-第九章-抽象类-概述

JAVA-初步认识-第九章-接口-细节