2

有时我更改了程序中的静态字段,但是当程序运行时,它仍然会获取旧数据。即使我重建工作区,它也不起作用。
我使用 Eclipse。编译器是否缓存常量值?我该如何避免这个问题?

Class Container {
    public static String message = new String("original");
}

Class B {
    public void printString() { System.out.println(Container.message); }
}

运行程序时,会打印出“original”。后来我将 Container.message 更改为“已更改”,即使我已经构建了工作区,我的程序仍会打印出“原始”。这对我来说很奇怪。

4

4 回答 4

3

内联

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

它打印test

static来自,final字段的字符串被内联到B类中。


如果我们final从字段中删除修饰符X,此示例将失败。

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 编译器不同。

如果你的课程有问题。反编译

javap -c B.class

并检查它是否访问您想要的字段

3: getstatic     #3                  // Field A.X:Ljava/lang/String;

还是内联

3: ldc           #3                  // String test
于 2013-07-04T07:25:11.530 回答
2

您似乎对静态场有完全错误的看法。静态字段是类变量,即所有对象将共享应用程序的一份副本。但是 JVM 不会为程序的不同运行保留静态字段。因此,期望如果您在一次运行中设置一些静态字段值,那么您将获得相同的字段值,这是一个完全错误的概念。

如果您想保留这些值,请进行序列化,但即使这样也是为了存储对象的状态,而不是真正用于静态字段。

于 2013-07-04T07:16:22.053 回答
0

你可以试试下面的代码。它对我来说非常有用。

class  MainClass {

    public static void main(String a[]){
        //before changing the value
        System.out.println(" before changing the value ");
        B b = new B();
        b.printString();

        //changing the value
        Container.message = "changed";
        System.out.println(" after changing the value ");
        b.printString();
    }
}


class Container {
    public static String message = new String("original");
}

class B {
    public void printString() { System.out.println(Container.message); }
}
于 2013-07-04T07:45:27.950 回答
0

这有时会在 Eclipse 中发生,特别是在旧版本中(Eclipse 4.x 没有这个问题)。尝试清理生成的.class并再次构建它们(Project -> Clean...)。还要确保Project -> Build Automatically选中,以便每次更改某些内容时都会自动调用编译器。如果这不起作用,请尝试重新启动 Eclipse ( File -> Restart)。

于 2013-07-04T08:57:06.647 回答