Java:不同执行中的静态字段行为

glm*_*ndr 3 java static

我有这门课:

package scripts;

public class TestStatic {
    public static void main(String[] args) {
        new IncrA().incrStatic();
    }
}

class Static {
    public static int CPT = 0;
}

class IncrA{
    public void incrStatic(){
        for (int i:Range.ints(0,100)){
            System.out.println("Now with "+this.toString()+" : Static.CPT="+Static.CPT);
            Static.CPT++;
            try{
                Thread.sleep(100);
            }
            catch(Exception e){
                e.printStackTrace();
            }
        }
        System.out.println("Finally for execution of "+this.toString()+" : Static.CPT="+Static.CPT);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我从命令行在java中运行类TestStatic两次.

javaw -cp ... scripts.TestStatic > 1.txt
javaw -cp ... scripts.TestStatic > 2.txt
Run Code Online (Sandbox Code Playgroud)

我原以为第一次和第二次执行会干扰,最后得到Static.CPT == 200的值,因为我认为JVM只会加载一次Static类.似乎并非如此.虽然我喜欢它,但我想知道我的这个例子是否足以得出结论JVM完全分离了exectutions.实际上,当我读取输出时,我的IncrA对象的hashCode在两次执行中通常是相同的:

从1.txt:

...
Now with scripts.IncrA@19f953d : Static.CPT=72
Now with scripts.IncrA@19f953d : Static.CPT=73
Now with scripts.IncrA@19f953d : Static.CPT=74
Now with scripts.IncrA@19f953d : Static.CPT=75
...
Run Code Online (Sandbox Code Playgroud)

从2.txt:

...
Now with scripts.IncrA@19f953d : Static.CPT=72
Now with scripts.IncrA@19f953d : Static.CPT=73
Now with scripts.IncrA@19f953d : Static.CPT=74
Now with scripts.IncrA@19f953d : Static.CPT=75
...
Run Code Online (Sandbox Code Playgroud)

@19f953d是两次执行之间共享.

我搜索了关于static关键字的深层解释但没有找到关于这些问题的任何内容.有人可以解释或给出一个很好的指针吗?

And*_*yle 9

简短的回答:static变量仅在单个JVM运行中持续存在,因此在第一次执行退出后,CPT设置为100 的事实实际上已丢失.有关静态变量和非静态变量的入门知识,请参见http://java.sun.com/docs/books/tutorial/java/javaOO/classvars.html.简而言之,唯一的区别是静态变量由类的所有实例共享 - 否则,它们的行为基本相同.

长(呃)答案是静态变量有点像实例变量,但对于Class类的对象.当JVM退出时,所有类都被卸载,因此静态变量不再存在,就像该类的任何实例不再存在一样.当您为第二次运行重新启动Java时,它会从您的(已编译的)源文件中重新读取类的定义,并CPT按照您的要求将其设置为零.

(在你提到的情况下,一次运行两个JVM会导致两个ClassLoaders和两个不同的Class对象,每个JVM一个,所以它们每个都有自己的静态变量版本.)

如果要在Java执行之间保留任何信息,则需要将其存储在外部(例如文件或数据库)的某个位置,并在启动时加载此信息.如果要在运行的Java进程之间共享信息,则需要让它们相互通信以共享此信息(例如,通过TCP连接).无论所讨论的变量是否是静态的,都是如此.