在什么情况下调用类中static final修饰的属性时不需要初始化类
被final修饰静态字段在操作使用时,不会使类进行初始化,因为在编译期已经将此常量放在常量池。
测试:class ClassLoadTime{
static{
System.out.println("ClassLoadTime类初始化时就会被执行!");
}
public static final int MIN = 10; (防止测试类和此类不在一个包,使用public修饰符)
}
class ClassLoadDemo{
public static void main(String[] args){
System.out.println(ClassLoadTime.MIN);
}
}
由于编译器编译优化,导致该变量在常量池中,当你用ClassLoadTime.MIN时,只会到常量池中查该数值,不会加载ClassLoaderTime类。输出:
10
————————————————
版权声明:本文为CSDN博主「冰凌其」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xiao1_1bing/article/details/81139926
在看到上述文章的这段内容时有一个疑问,如果我访问的属性类型是一个引用类型的话也不会初始化 ClassLoaderTime类吗?于是用一下代码测试了一下:
public class HungrySingletonPattern {
static{
System.out.println("HungrySingletonPattern类初始化时就会被执行!");
}
public static final HungrySingletonPattern instance = new HungrySingletonPattern();
public static final String str = "调我不用初始化类!";
private HungrySingletonPattern() {
super();
// TODO Auto-generated constructor stub
}
public static final HungrySingletonPattern getInstance(){
return instance;
}
}
public class Test {
public static void main(String[] args) throws SecurityException, NoSuchFieldException {
HungrySingletonPattern i = HungrySingletonPattern.instance;
// String s = HungrySingletonPattern.str;
}
}
运行结果如下:
HungrySingletonPattern类初始化时就会被执行!
说明这个HungrySingletonPattern类被初始化了!为什么上边的例子不会初始化类,在把类中属性换成引用类型时类就会被初始化呢?上边的例子说是编译器的优化导致的,那么我们就来看看两段代码生成的字节码有什么区别吧:
1. main函数中调用HungrySingletonPattern.str的情况:
Code:
stack=1, locals=2, args_size=1
0: ldc #21 // String 调我不用初始化类!
2: astore_1
3: return
2. main函数中调用HungrySingletonPattern.instance的情况:
Code:
stack=1, locals=2, args_size=1
0: getstatic #21 // Field cn/edu/xidian/singleton/h
ungry/HungrySingletonPattern.instance:Lcn/edu/xidian/singleton/hungry/HungrySing
letonPattern;
3: astore_1
4: return
我们发现上述两个例子中生成的字节码唯一的区别就是1中生成的指令是ldc指令,而2中生成的指令是getstatic指令。那么这两个指令都是什么含义呢?
我们通过查询java虚拟机规范发现指令的解释如下:
0xb2 | getstatic | 获取指定类的静态域,并将其值压入栈顶。 |
0x12 | ldc | 将 int,float 或 String 型常量值从常量池中推送至栈顶。 |
所以我们可以大胆的推测:当类中的基本类型或String类型在被static final修饰时,编译器会将指令直接优化成ldc指令,从而在只获取该属性的值时,不需要初始化它所在的类;而当被static final修饰的属性为引用类型时,由于编译器无法直接将其转化为常量,故在获取该类型的属性时还是需要初始化类的。