new的后面做了什么?new 干了至少14件事--Java极限内存分析2

本文详细解析了Java中父类与子类构造器的执行顺序及成员变量初始化过程,并探讨了静态与非静态代码块的执行时机,以及方法重写带来的多态特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主程序:

package selfimpr.test; public class TestDynamicLocked { /** * @param args */ public static void main(String[] args) { new Child(); } }

父类:

package selfimpr.test; public class Parent { public static int a = 1; static { a = 2; p1(); } public int b = 3; { b = 4; p1(); p2(); } public Parent(int a) { } public static void p1() { System.err.println("Parent-a: " + a); } public void p2() { System.err.println("Parent-a: " + a); System.err.println("Parent-b: " + b); } }

子类:

package selfimpr.test; public class Child extends Parent { public static int a = 11; static { a = 21; p1(); } public Child() { //由于Parent没有无参构造器,所以必须显示调用一次父类构造器. //以便Child的对象持有super引用. super(a); //调用此方法时,访问的是父类中的a,此时不能访问Child中的a. } public Child(int arg1) { //每个构造器都必须能够让编译器知道通过该构造器可以让Child对象持有super引用. //并且调用父类构造器的那一句必须是第一句. //例如this();进入Child的无参构造器,Child的无参构造器的第一句是super(a); // this(); super(arg1); } public int b = 31; { b = 41; p1(); p2(); } public static void p1() { System.err.println("Child-a: " + a); } public void p2() { System.err.println("Child-a: " + a); System.err.println("Child-b: " + b); } }

内存分析:

1. 进入ClassLoader的loadClassInternal(String name)方法,加载Child类.
2. 同1,加载Parent类.
3. 初始化Parent的静态成员变量.Parent.a=1;
4. 调用Parent的静态代码块.Parent.a=2;执行方法p1();此时,调用的p1方法是Parent类的.所以输出Parent-a: 2.实际调用了Parent.p1(Parent.a);
5. 初始化Child的静态成员变量.Child.a=11;
6. 调用Child的静态代码块.Child.a=21;执行方法p1();此时调用的p1方法是Child类的.所以输出Child-a: 21.实际调用了Child.p1(Child.a);
7. 此时,类的加载,以及静态成员变量,静态语句块执行完毕.
8. 下面才真正开始进入new Child();
9. 首先进入的当然是Child的无参构造器中的super(a);这一句.
10. 进入Parent的Parent(int a)这个构造器.
11. 这个构造器其实是有隐式的super();这一句的.他是去调用了java.lang.Object的无参构造器,再向里,就是JVM的内幕了,我们就不参与了.
12. 调用完父类的构造器之后,下一步工作就是初始化成员变量.因此Parent的成员变量b=3执行.
13. 执行Child的动态语句块.b=4的赋值自然是Parent对象的成员变量b=4;一定注意,此时Child的成员变量b=0;调用p1()方法,由于是静态的,所以输出Parent自己的东西.调用p2()方法的时候,动态方法被重写,多态存在,所以这里输出的Child-b: 0,很明显,这里调用了子类的方法(p2);
14. 动态语句块执行完,就该执行Parent的构造器中super()之后的语句了.这里要注意,虽然Parent(int a)这个构造器中没有代码,但隐式的有一个super();由于后面再没有代码,所以Parent(int a)这个构造器就算执行完毕了,下面进入子类Child的构造器.
15. 当然,还是成员变量的初始化,b=31.
16. 然后,执行动态语句块,b=41.
17. 调用p1方法,是Child的p1方法.所以输出Child-a: 21;
18. 进入p2方法,调用的方法是Child的p2()方法,此时Child的成员变量b=41,当然输出的是Child-b:41;
19. 当这些过程全部执行完毕之后,整个构造器就算执行完毕了.
看看上面这些过程,new一个对象需要耗费多少的精力?
让我们看一看顺序:
加载子类, 加载父类, 初始化父类静态成员变量, 执行父类静态语句块, 初始化子类静态成员变量, 执行子类静态语句块, 调用子类的构造器, 调用父类的构造器, 初始化父类的成员变量, 执行父类的动态语句块, 执行父类构造器中的其他代码, 初始化子类的成员变量, 执行子类的动态语句块, 执行子类构造器中的其他代码, 一个对象被创建.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值