源代码如下,求结果
public classMemoryAnalyse {public static int k = 0;public static MemoryAnalyse t1 = new MemoryAnalyse("t1");public static MemoryAnalyse t2 = new MemoryAnalyse("t2");public static int i = print("i");public static int j = print("j");public static int n = 99;
{
print("constructor code");
}static{
print("static code");
}public static intprint(String s) {
System.out.println("i=" + i + " " + s + " k=" + k + " n=" +n+ " j=" +j);++i;++k;++n;returni;
}publicMemoryAnalyse(String string) {
print(string);
}public static void main(String[] args) throwsClassNotFoundException {
MemoryAnalyse d= new MemoryAnalyse("T");
}
}
然而结果是这个
i=0 constructor code k=0 n=0 j=0i=1 t1 k=1 n=1 j=0i=2 constructor code k=2 n=2 j=0i=3 t2 k=3 n=3 j=0i=4 i k=4 n=4 j=0i=5 j k=5 n=5 j=0i=6 static code k=6 n=99 j=6i=7 constructor code k=7 n=100 j=6i=8 T k=8 n=101 j=6
有没有很惊讶,结果竟然这么复杂.好,下面我们分析一下,在分析之前,先普及下不怎么用的基础知识
代码块和静态代码块何时运行问题:
代码块在创建对象时运行
静态代码块在类加载时运行
大家都知道static是属于类的并非对象,也就是说static修饰的东西都会在class加载到方法区时就存在在那里.所以方法区中类加载时内存过程如下
1.当类刚加载时会全部加载到方法区时,此时所有变量全部未实例化.
2.实例化参数t1
此时因为代码块在创建对象时执行,且在构造函数之前执行,所以先执行代码块
{
print("constructor code");
}
因为此时所有的变量都为默认值,所以执行后打印结果为
i=0 constructor code k=0 n=0 j=0
此时i,n,k的值都已经自加一,值为1
然后实例化调用构造函数
publicMemoryAnalyse(String string) { //这里string为t1
print(string);
}
构造函数调用结果如下
i=1 t1 k=1 n=1 j=0
此时i,n,k的值都已经自加一,值为2
3.实例化参数t2
和第一步一样在构造函数之前执行代码块
{
print("constructor code");
}
i=2 constructor code k=2 n=2 j=0
此时i,n,k的值都已经自加一,值为3
然后实例化调用构造函数
publicMemoryAnalyse(String string) { //这里string为t2
print(string);
}
构造函数调用结果如下
i=3 t2 k=3 n=3 j=0
此时i,n,k的值都已经自加一,值为4
4.初始化参数i
这里直接调用print("i")函数,得到结果为
i=4 i k=4 n=4 j=0
此时i,k,j值为5,注意i的值不是通过自加一变成5的,而是通过函数的返回值赋给i的
5.初始化参数j
这里和上一步一样,执行print("j"),然后把函数的返回值赋给j,打印结果为
i=5 j k=5 n=5 j=0
此时j的值已经为6
到这里类加载的内部参数变化就完成了,我们可以用加载类的方式调用一下
public static void main(String[] args) throwsClassNotFoundException {//MemoryAnalyse d = new MemoryAnalyse("T");
Class.forName("MemoryAnalyse");
}
Class.forName(类名字符串)是手动加载类到方法区,得到结果为
i=0 constructor code k=0 n=0 j=0i=1 t1 k=1 n=1 j=0
i=2 constructor code k=2 n=2 j=0
i=3 t2 k=3 n=3 j=0
i=4 i k=4 n=4 j=0
i=5 j k=5 n=5 j=0
i=6 static code k=6 n=99 j=6 //这行的出现是因为static代码段在类加载时执行.n=99是因为类加载了,n的初值为99把之前的值覆盖掉了
然后改为我们之前的demo
public static void main(String[] args) throwsClassNotFoundException {
MemoryAnalyse d= new MemoryAnalyse("T");//Class.forName("MemoryAnalyse");
}
执行结果为
i=0 constructor code k=0 n=0 j=0//t1代码块执行
i=1 t1 k=1 n=1 j=0//t1构造函数执行
i=2 constructor code k=2 n=2 j=0//t2代码块执行
i=3 t2 k=3 n=3 j=0//t2构造函数执行
i=4 i k=4 n=4 j=0
i=5 j k=5 n=5 j=0
i=6 static code k=6 n=99 j=6//静态代码块执行
i=7 constructor code k=7 n=100 j=6//T代码块执行
i=8 T k=8 n=101 j=6 //T构造函数执行
最后两行的出现就很简单了,一个是代码块的,一个是构造函数的
这么一分析是不是简单了很多