您的位置:首页 > 编程语言 > Java开发

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

2009-04-10 12:21 351 查看
主程序:

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一个对象需要耗费多少的精力?
让我们看一看顺序:
加载子类, 加载父类, 初始化父类静态成员变量, 执行父类静态语句块, 初始化子类静态成员变量, 执行子类静态语句块, 调用子类的构造器, 调用父类的构造器, 初始化父类的成员变量, 执行父类的动态语句块, 执行父类构造器中的其他代码, 初始化子类的成员变量, 执行子类的动态语句块, 执行子类构造器中的其他代码, 一个对象被创建.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: