java 内存 面试题_看起来很懵的java内存加载面试题

源代码如下,求结果

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.当类刚加载时会全部加载到方法区时,此时所有变量全部未实例化.

658a70070cb407e1d2a504769bb247b1.png

2.实例化参数t1

1144df2ce0b5dcb61eeb7d63a01c9377.png

此时因为代码块在创建对象时执行,且在构造函数之前执行,所以先执行代码块

{

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

57547dd44a1d82fdf8a57a4832a2c60d.png

和第一步一样在构造函数之前执行代码块

{

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

01d4e1b68d6fb3d6b040593a4b6367c2.png

这里直接调用print("i")函数,得到结果为

i=4   i  k=4  n=4   j=0

此时i,k,j值为5,注意i的值不是通过自加一变成5的,而是通过函数的返回值赋给i的

5.初始化参数j

9524b414206b5b45f40188b9f0b14b3d.png

这里和上一步一样,执行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构造函数执行

最后两行的出现就很简单了,一个是代码块的,一个是构造函数的

这么一分析是不是简单了很多

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值