上篇我们介绍了java中的构造方法,了解了关键字this和super在继承中所起到的作用,this可以显式调用重载的构造方法,super可以显式的调用父类中的任意可见方法。了解方法重载和重写的区别,知道了关键字final的作用,本篇将以一段代码介绍实例化对象时内存的状态。 如果你能看懂以下代码,那本篇你就不用浪费时间了。
/*这是父类*/public class Base { public Base(){ PRint(); } public void print(){ }}//这是子类public class Child extends Base { private int a = 2; public void print(){ System.out.println(a); }}//main函数public class Test2 { public static void main(String[] args){ Base b = new Child(); b.print(); }}输出结果:02四、new关键字的背后 我们知道在java中所有的方法都是在类中的,包括main方法。所以程序开始做的第一件事情是:加载类,就是将类的信息加载到内存中,一个类的信息主要有:
静态变量静态初始化代码块静态方法实例变量实例初始化代码块实例方法对继承自父类的信息的引用 类的加载过程如下:首先在内存堆中开辟内存以存放当前类对类中的属性赋默认初始值(int默认为0,boolean默认为false,引用类型默认为null)调用构造函数进行对象初始化(首先默认执行super调用父类构造函数)父类构造函数初始化完成之后回到子类完成子类的显式初始化最后将该对象赋值给引用对象 下面就介绍一下,Base b = new Child();这条语句,内存的实时状态。 内存主要有栈和堆构成,栈中主要存放局部变量,b这个引用就存放其中,堆中主要存放引用的实际内容这下我们从b.sayHello()说起,首先查看b的实际类型(发现是child类型),于是从child实例对象中查找此方法,找到了,然后直接执行输出hello child本条语句执行完成,接下来执行b.showName();,依然从child对象中查找,没有找到,于是jvm深入到父类对象中,找到并执行输出结果。 总结下,java中总是从当前对象的实际类型出发搜索方法,子类中没有找到的话就会深入父类中搜索,如果父类中也没有找到就会报错 之后为了改进这种搜索效率,使用了虚方法表,也就是将每个类的所有方法(包含父类的方法引用)存放到一张虚拟表中,每次调用方法时候,查找表以加快效率。 最后我们根据以上所有内容,解析本文刚开始的一段代码。 第一句:Base b = new Child();,加载Base类,创建局部变量b存放栈中,发现child类未加载于是去加载child类,按照以上介绍的加载过程,首先开辟了内存以存放类的内容,将private int a;初始化为0。执行new操作,并调用child类的构造方法,转去调用Base类的构造方法,调用函数print,于是判断出此对象的实际类型是child,在child类中查找print找到并执行输出还未显式初始化的a=0,然后返回Base构造方法中,结束父类构造方法,转回执行child构造方法,结束child构造方法完成属性的显式初始化,a=2,结束本条语句。 第二句:b.print();再次搜索print执行输出2,结束。 本文若有不当之处,还望大神不吝赐教,tk。
新闻热点
疑难解答