java中类的加载与实例化顺序

首先来看一段程序,通过它的输出来分析类的加载以及实例化的机制。
public class T  implements Cloneable {
	public static int k = 0;
	public static T t1 = new T("t1");
	public static T t2 = new T("t2");
	public static int i = print("i");
	public static int n = 99;

	public int j = print("j");
	
	{
		print("构造块");
	}

	static {
		print("静态块");
	}

	public T(String str) {
		System.out.println((++k) + ":" + str + "    i=" + i + "  n=" + n);
		++n;
		++i;
	}

	public static int print(String str) {
		System.out.println((++k) + ":" + str + "   i=" + i + "   n=" + n);
		++n;
		return ++i;
	}
	
	public static void main(String[] args) {
		
	}
}

输出:
1:j   i=0   n=0
2:构造块   i=1   n=1
3:t1    i=2  n=2
4:j   i=3   n=3
5:构造块   i=4   n=4
6:t2    i=5  n=5
7:i   i=6   n=6
8:静态块   i=7   n=99

首先从main函数进入程序,类中的静态成员会被先加载,加载的时候,JVM首先将类中静态属性的声明和静态方法的声明加载到内存中(方法区中),然后将静态属性赋值,之后执行静态块中的代码。如果在类加载的时候遇到实例化的情况,首先加载普通属性的声明,然后普通方法的声明,之后是普通属性赋值,执行构造块代码,最后执行构造函数中的代码。如果有继承关系,父类优先于子类。这是基本的加载顺序。
接下来我们逐行来分析。首先加载类中的静态属性声明,(static )int k, T t1, T t2, int i, int n, (只有声明还没有赋值),然后加载静态方法声明static int print(String str) {}。之后对静态属性赋值,首先加载k = 1; 当加载到t1 = new T("t1")时,这是实例化的过程,这时类暂时不加载。按照上面所说的,实例化的时候首先加载类中的普通成员声明 int j, 然后是普通方法声明,public T(String str){},之后对普通属性赋值,这时j = print("j"), 就调用了public static int print(String str){} 方法,这时的i和n还没有被赋值,仅仅是JVM在声明时给它分配的初始值,都为0。因此这时的输出为1:j   i=0   n=0。这是普通属性的赋值,接下来是构造块的执行因此有了第二行输出:2:构造块   i=1   n=1,最后是构造函数执行,有了第三行输出:3:t1    i=2  n=2。到现在t1的实例化过程结束,接着进行类的加载。 接下来对t2进行复制,也是一个实例化的过程,和上面蓝色字体描述的一样, 于是就有了4,5,6三行输出。再下面对static int i进行复制 i = print("i") 因此有了第七行输出。接下来对public static n 进行赋值, n = 99。此时静态属性赋值全部结束,最后加载静态块中的内容,print("静态块"), 因为这时的n已经被赋值了,因此最后的输出为:8:静态块   i=7   n=99

猜你喜欢

转载自kickcode.iteye.com/blog/2275580