可确定常量
通常意义上的常量,都是可确定常量,对于可确定常量,在类加载时满足:常量在编译阶段会存入待调用这个常量的方法所在的类的常量池中,本质上。调用类并没有直接引用到定义常量的类,因此并不会触发定义常量的类的初始化
public class MyTest2 {
public static void main(String[] args) {
System.out.println(MyParent2.str);
}
}
class MyParent2 {
public static final String str = "hello world";
static {
System.out.println("MyParent2 static block.");
}
}
以上代码的运行结果是:
由上图的运行结果可以看出,MyParent2
这个类并没有初始化,使用反编译工具在MyTest2
这个类的常量池中可以看到字符串:hello world
,进一步证明了:常量在编译阶段会存入待调用这个常量的方法所在的类的常量池中,
因为hello world
已经存入到MyTest2
的常量池中了,所以在编译后,MyParent2.class
就没有任何作用了,甚至我们可以把MyParent2.class
文件删掉,再次运行,仍然可以正常运行。
不可确定常量
对于常量,普遍的认知是不可变的,但是在常量是一个随机字符串的情况下,每次运行,其值在运行前是不可确定的,但是在运行后就是确定的。这种常量,可以称之为:不可确定常量
。如:public static final String str = UUID.randomUUID().toString();
对于不可确定常量,上面的结论并不适用。
public class MyTest3 {
public static void main(String[] args) {
System.out.println(MyParent3.str);
}
}
class MyParent3 {
public static final String str = UUID.randomUUID().toString();
static {
System.out.println("MyParent3 static block.");
}
}
其运行结果如下:
由上图的运行结果可以看出来:不可确定常量,会导致定义该常量的类在运行时初始化。
结论:
- 可确定常量:在编译阶段会存入待调用这个常量的方法所在的类的常量池中,本质上。调用类并没有直接引用到定义常量的类,因此并不会触发定义常量的类的初始化
- 不可确定常量:当一个常量的值并非编译阶段可以确定的,那么其值就不会被放到调用类的常量池中。这时在程序运行时,会导致主动使用这个常量所在的类,显然会导致这个类被初始化。