Как обрабатываются статические финальные и статические члены в Java? - PullRequest
0 голосов
/ 18 февраля 2019

Я уже видел несколько вещей о статических переменных здесь, в переполнении стека и в других местах в Интернете.Однако ответы мне не ясны.Когда я думаю, что нашел ответ, какой-то другой источник противоречит утверждению (или, по крайней мере, я так думаю).

Например: m0bius сообщает нам в Как работает ключевое слово static в Java? (в разделе «Когда создается эта копия [ред. Статическая переменная]?»), Что статические переменные создаются во время выполнения.Но если я проверю https://en.wikipedia.org/wiki/Class_variable (раздел «Статические переменные-члены и статические функции-члены»), это скажет мне, что в некоторых языках происходит обратное, и то же самое происходит в других языках.

Мой вопрос здесь может бытьразделены на два разных вопроса:

  • В Java статические переменные класса, созданные во время выполнения или во время компиляции?
  • В Java* окончательные статические переменные класса, созданные во время выполнения или во время компиляции?

Что я имею в виду в зависимости от времени компиляции:

  • время компиляции: когда компилируется исходный код (например, при создании .class-файла)
  • время выполнения: когда программа фактически выполняется

Некоторый код используется только дляЦель этого вопроса:

// MyClass.java
public class MyClass {
    public static int instances;
    public final static double PI = 3.14159265359

    public MyClass() {
        instances++;
    }
    // ...
}

// Main.java ; version 1
public class Main {
    public static void main(String args[]) {
        System.out.println("I am doing nothing with MyClass");
    }
}
// OUTPUT: I am doing nothing with MyClass

// Main.java ; version 2
public class Main {
    public static void main(String args[]) {
        System.out.println("PI = " + MyClass.PI);
        MyClass obj1 = new MyClass();
        MyClass obj2 = new MyClass();
        System.out.println("instances = " + MyClass.instances);
    }
}
OUTPUT:
3.14159265359
2

Если обе переменные static и final static будут созданы во время выполнения, в первой версии Main ни одна из обеих статическихпеременные (экземпляры и PI) класса MyClass будет создан.Но я бы ожидал, что окончательная статическая переменная PI *1037* будет создана во время компиляции (так что она будет "встроена" в .class-файл), потому что я думаю, что это будет иметь лучшую производительность (нетНезависимо от того, что происходит с классом MyClass, PI всегда будет 3.14159265359, поэтому он также может быть помещен в двоичный файл).
Это может быть то же самое со статической переменной, но может изменяться во всей программе.

1 Ответ

0 голосов
/ 18 февраля 2019

Являются ли в Java статические переменные класса, созданные во время выполнения или во время компиляции?

Никакие переменные не "создаются" во время компиляции в Java, если под созданным вами подразумеваетсявыделены и инициализированы.Все они создаются во время выполнения.Независимо от того, являются ли они static или static final, не имеют отношения к , когда они выделяются.

Но я бы ожидал, что конечная статическая переменная PI будетсоздан во время компиляции (поэтому он будет «встроен» в .class-файл), потому что я думаю, что это будет иметь лучшую производительность ...

Это не так, как это работает в Java.Когда файлы классов «скомпилированы», они в основном кодируются.Конечно, есть некоторая работа, которая выполняется, но очень большой процент того, что мы думаем о компиляции (в терминах таких языков, как C), происходит во время выполнения.Это особенно верно, когда мы смотрим на оптимизацию и встраивание.

Компилятор выполняет некоторую предварительную работу, такую ​​как возможность предварительного вычисления значений полей (статических или экземпляров) заранее, если это возможно.Например, если вы определяете свое поле следующим образом, то умножения будут выполняться во время компиляции:

private long timeoutMillis = 10 * 24 * 3600 * 1000;

Это также верно для String с, где компилятор будет добавлять константные строки вместе, если это возможно,Следующее не использует StringBuilder во время выполнения, но вместо этого создаст один String во время компиляции:

private static final String DEFAULT_HEADER = "A long headers that is " +
   "broker into two lines\n";

Но все же, в обоих случаях, распределение и инициализация полей (long timeoutMillis и String DEFAULT_HEADER) выполняется во время выполнения.

Если во время выполнения будут созданы как статические, так и конечные статические переменные, в первой версии Main нет ни обеих статических переменных (экземпляров и PI)) класса MyClass.

В вашем примере поля static (final или нет) выделяются и инициализируются, когда класс загружен дляпервый раз.Таким образом, в ваших первых Main полях instances или PI static никогда не будет создано, как вы упомянули.В вашем втором примере.как только ссылка на MyClass будет загружена, файл класса будет загружен и поля static будут созданы.

...