Java: поведение статических полей в разных исполнениях - PullRequest
3 голосов
/ 06 октября 2009

У меня есть этот класс:

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);
    }
}

Теперь я дважды запускаю класс TestStatic в Java из командной строки.

javaw -cp ... scripts.TestStatic > 1.txt
javaw -cp ... scripts.TestStatic > 2.txt

Я ожидал, что первое и второе выполнения будут мешать, и в конце я получу значение для Static.CPT == 200, потому что я думал, что JVM будет загружаться только один раз в классе Static. Кажется, это не так. Хотя мне это нравится, мне интересно, достаточно ли этого примера, чтобы сделать вывод, что JVM полностью разделяет разделы. На самом деле, когда я читаю свои выходные данные, hashCode для моего объекта IncrA часто одинаков в обоих исполнениях:

От 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
...

От 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
...

@19f953d распределяется между двумя исполнениями.

Я гуглил для глубоких объяснений статического ключевого слова, но не нашел ничего об этих проблемах. Может кто-нибудь объяснить или дать хороший указатель?

Ответы [ 4 ]

9 голосов
/ 06 октября 2009

Краткий ответ: static переменные сохраняются только в течение одного запуска JVM, поэтому после первого выполнения программы факт, что для CPT было установлено значение 100, фактически теряется. См. http://java.sun.com/docs/books/tutorial/java/javaOO/classvars.html для начинающих по статическим и нестатическим переменным. Вкратце, единственное отличие состоит в том, что статические переменные являются общими для всех экземпляров класса, в противном случае они в основном ведут себя одинаково.

Длинный (er) ответ заключается в том, что статические переменные подобны переменным экземпляра, но для объекта Class для вашего класса. Когда JVM завершает работу, все классы выгружаются, поэтому статические переменные больше не существуют, как и любые экземпляры класса. Когда вы перезапускаете Java для второго запуска, он перечитывает определение ваших классов из ваших (скомпилированных) исходных файлов и устанавливает CPT в ноль, как вы и просили.

(А в упомянутой вами ситуации одновременный запуск двух JVM приводит к двум ClassLoaders и двум отдельным Class объектам, по одному на JVM, поэтому у каждого из них есть свои версии статической переменной.)

Если вы хотите сохранить какую-либо информацию между выполнениями Java, вам нужно будет сохранить ее где-то вне (например, в файле или базе данных) и загрузить эту информацию при запуске. Если вы хотите обмениваться информацией между запущенными процессами Java, вам нужно, чтобы они общались друг с другом для обмена этой информацией (например, через TCP-соединения). Это верно независимо от того, являются ли рассматриваемые переменные статическими или нет.

1 голос
/ 06 октября 2009

Вы запустили две копии JVM, и каждая копия загрузила экземпляр Static. Кстати, статические классы уникальны для каждого загрузчика классов, поэтому на самом деле можно получить два экземпляра в одной и той же JVM.

Лучше избегать использования ключевых слов в качестве идентификаторов (статических), даже если они написаны заглавными буквами.

1 голос
/ 06 октября 2009

статические поля являются статическими только в пределах одной JVM, то есть одного выполнения. Создание "@ 19f953d" не определено и может совпадать или не совпадать для двух последовательных выполнений.

0 голосов
/ 06 октября 2009

Ничего не сохраняется между вызовами JVM.

Статика используется всеми экземплярами одного и того же класса, но не для JVM.


Даже если они запускаются одновременно, это не имеет значения. Они не общаются, у каждого свое пространство памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...