有时我更改了程序中的静态字段,但当程序运行时它仍然会获取旧数据。即使我重建了工作区,它也无法工作。
我使用Eclipse。编译器是否缓存常量值?如何避免这个问题?
Class Container {
public static String message = new String("original");
}
Class B {
public void printString() { System.out.println(Container.message); }
}
运行程序时,会打印出“original”。后来我将 Container.message 更改为“已更改”,即使我已经构建了工作区,我的程序仍会打印出“原始”。这对我来说很奇怪。
最佳答案
内联
带有 static
和 final
修饰符的字段由编译器内联。仅具有 static
修饰符的字段不会内联。
我们上两个类
class A {
static final String X = "test";
}
class B {
public static void main (String... args) {
System.out.println(A.X);
}
}
编译它们,删除A
类,然后运行B
类
javac A.java B.java
rm A.class
java B
它打印测试
。
来自 static
、final
字段的字符串已内联到 B
类中。
如果我们从 X
字段中删除 final
修饰符,此示例将失败。
class A {
static String X = "test";
}
class B {
public static void main (String... args) {
System.out.println(A.X);
}
}
编译它们,删除A
类,然后运行B
类
javac A.java B.java
rm A.class
java B
我们得到
Exception in thread "main" java.lang.NoClassDefFoundError: A
at B.main(B.java:3)
Caused by: java.lang.ClassNotFoundException: A
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more
为了避免过时的内联值问题,请立即重新编译所有源。
类加载器
如果 A
类使用两个不同的类加载器加载,则可能会出现另一个问题。这将产生 A
类的两个副本。更改一个字段中的 static
字段的值对于引用另一个字段中的 static
字段的代码将不可见。
编译器问题
请注意,Eclipse 使用自己的 Java 编译器,其行为与 JDK 编译器不同。
如果你的类(class)有问题。反编译它
javap -c B.class
并检查它是否访问了您想要的字段
3: getstatic #3 // Field A.X:Ljava/lang/String;
或者它是内联的
3: ldc #3 // String test
关于java - 静态字段不更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17463973/