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

Java类加载过程中的一点小陷阱

2016-10-21 11:21 162 查看

0.问题阐述

最近看到一到面试题,答案让人非议所思。

代码

/**
* 类的初始化测试
* @author Jason
*
*/
public class Single {

private static Single instance = new Single();
public static int count1;
public static int count2 = 0;

public Single() {
count1++;
count2++;
}
public static Single getInstance(){
return instance;
}

public static void main(String[] args) {
System.out.println("count1 = "+Single.count1);
System.out.println("count2 = "+Single.count2);
}
}


结果

count1 = 1

count2 = 0

很奇怪对不对,count1和count2的区别就是count1没有赋初始值,然后结果就不同了。然后把这句代码
private static Single instance = new Single();
放到count2声明的后面,就会发现输出的结果是1。结果很匪夷所思,但是其实是类的加载过程导致的必然结果,只要学习一下类的加载过程就可以理解了。下面先介绍一下类的加载过程。

1. 类的加载过程

JVM将类加载过程分为三个步骤:装载(Load),链接(Link)和初始化(Initialize),其中链接又分为三个步骤。

1.加载:查找并加载类的二进制数据

2.链接

① 验证:确保被加载的类的正确性

② 准备:为类的静态变量分配内存,并将其初始化为默认值

③ 解析:把类中的符号引用转换为直接引用

3.初始化:为类的静态变量赋予正确的初始值(这个不是默认值)

每个步骤就不在此详细介绍了,我们需要关注的是链接的第二个步骤准备,还有类加载过程的第三个步骤初始化,这两个步骤看起来很相像,但是是很不同的,默认值是指类的静态变量的数据类型的默认值,如数值型的默认值是0,布尔型的默认值是false,引用型的默认值是null。而初始值是指我们指定赋予给变量的,例如上面的
public static int count2 = 0;
中的0就是我们赋予变量的初始值,当然也可以是其它的整型数值。

看完类的加载过程我们还得了解一下Java程序对类的使用方式,因为这

类是否会被初始化有关

2. Java程序对类的使用方式

Java程序对类的使用方式可分为2种,主动使用被动使用,只有当类是主动使用的时候,才会进行类的初始化

2.1 主动使用

1.创建类的实例

2.访问某个类或接口的静态变量,或者对该静态变量赋值

3.调用类的静态方法

4.反射(如Class.forName(“edu.jyu.Test”))

5.初始化一个类的子类

6.Java虚拟机启动时被标明为启动类的类(如在命令行中敲java Test)

2.2 被动使用

除了上述六种情况,都是对类的被动使用,都不会导致类的初始化

3. 程序分析

好了,现在根据上面的这些知识,我们就可以揭开这个程序的面纱了,下面就详细说一下程序执行的过程。

1.从main方法开始,第一句代码是
System.out.println("count1 = "+Single.count1);
,这句代码中调用了Single类的静态变量count1,于是满足主动使用的第2条,于是类会被加载并且会被初始化。

2.在Single类被加载的时候,jvm会为类的静态变量分配内存,并且设置默认的初始值,于是变量instance 的值为null,count1和count2的值都为0。链接的准备阶段完毕。

3.因为SIngle类是主动使用,所有会进行类的初始化,即是将“=”右边的值赋给变量。变量instance的值就会等于 new Single()产生的对象的引用,而在new Single()中,又执行了count1++;count2++;所以此时count1和count2的值都变成了1。

4.接下来是为count1和count2赋初始值,因为count1没有指定初始值,所有count1还是等于1,而count2有初始0,所以将0赋给count2,于是最终答案就变为了count1=1,count2=0。

如果上面的内容有错误的地方或者讲的不好的地方,还请大家指点一下,我好及时修改
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息