Java常量的探索
先看代码:A.java
class A
{
public static void main(String[] args)
{
System.out.println(B.WORD);
}
}
B.java
class B
{
public static final String WORD = "测试1";
}
运行结果自然是:
测试1
注意了,现在将 B.java 中静态字段“测试1” 改为 “测试2”,然后重新编译 B.java,再运行A类
运行结果会是什么?
测试1
没错,不是测试2,是测试1。重新编译A.java,再次运行A类
运行结果:
测试2
这时就出现问题了,真正开发中,我们往往想通过维护一部分代码来改变程序的执行效果,而出现这种情况是会让我们始料未及的。
接下来,我们来详细的探究一下原因以及解决方案
将B.java改写成如下代码:
class B
{
static {
System.out.println("B被使用了");
}
public static final String WORD = "测试3";
}
编译运行程序,结果如下
测试3
程序并没有打印“B被使用了”,这是为什么呢?
通过 javap 反编译A类的class文件可得到如下信息:
class A {
A();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object.””:()V
4: return
public static void main(java.lang.String[]);
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4 // String 测试3
5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
}
3: ldc #4 // String 测试3
可以看出常量WORD被编译到A类的class文件中了,所以程序执行的时候并没有加载B类。也就不难明白为什么程序没有随着B类的改变而改变执行结果。
将AB两个java文件改写成如下代码:
class A
{
public static void main(String[] args)
{
System.out.println(B.WORD);
System.out.println(B.getWord());
}
}
class B
{
static {
System.out.println("B被使用了");
}
public static final String WORD = "测试3";
public static String getWord() {
return WORD;
}
}
程序执行结果:
测试4
B被使用了
测试4
由此可以得出,开发中使用常量时,一定要谨慎。考虑你的实现,决定是否使用get方法获取常量,或者直接使用枚举,或将常量写入配置文件。