Подтвердить что ты не робот

Когда инициализируются статические переменные?

Мне интересно, когда статические переменные инициализируются значениями по умолчанию. Правильно ли, что при загрузке класса статические вары создаются (распределяются), выполняются статические инициализаторы и инициализации в объявлениях? В какой момент указаны значения по умолчанию? Это приводит к проблеме прямой ссылки.

Также, пожалуйста, если вы можете объяснить это в связи с вопросом, заданным в Почему статические поля не инициализируются вовремя? и особенно ответ, данный Кевином Броком на тот же сайт. Я не понимаю третьего пункта.

4b9b3361

Ответ 1

  • Это переменная, которая принадлежит классу, а не объекту (экземпляру)
  • Статические переменные инициализируются только один раз, в начале выполнения.
  • Эти переменные сначала инициализируются, прежде чем инициализировать любые переменные экземпляра
  • Единая копия, которая будет использоваться всеми экземплярами класса
  • Статическая переменная может быть доступна непосредственно по имени класса и не нуждается в каком-либо объекте. См. Java Static Variable Methods.

Экземпляры и статические переменные автоматически инициализируются стандартными значениями по умолчанию, если вы не намеренно инициализируете их. Хотя локальные переменные не инициализируются автоматически, вы не можете скомпилировать программу, которая не может инициализировать локальную переменную или назначить значение этой локальной переменной до ее использования.

То, что на самом деле делает компилятор, - это внутреннее создание процедуры инициализации одного класса, которая объединяет все инициализаторы статических переменных и все статические блоки инициализатора кода в том порядке, в котором они появляются в объявлении класса. Эта единственная процедура инициализации запускается автоматически, только один раз, когда класс загружается первым.

В случае внутренних классов они не могут иметь статические поля

Внутренний класс - это вложенный класс, который явно или неявно объявленный статический. Внутренние классы не могут объявлять статические инициализаторы (§8.7) или интерфейсов членов. Внутренние классы не могут объявлять статические членов, если они не являются постоянными полями времени компиляции "

См. JLS 8.1.3 Внутренние классы и экземпляры Enclosing

final поля в Java могут быть инициализированы отдельно от места их объявления, однако это не применимо к полям static final. См. Пример ниже.

final class Demo
{
    private final int x;
    private static final int z;  //must be initialized here.

    static 
    {
        z = 10;  //It can be initialized here.
    }

    public Demo(int x)
    {
        this.x=x;  //This is possible.
        //z=15; compiler-error - can not assign a value to a final variable z
    }
}

Это связано с тем, что существует только одна копия переменных static, связанных с типом, а не одна, связанная с каждым экземпляром типа, как с переменными экземпляра, и если мы попытаемся инициализировать z типа static final внутри конструктора, он попытается повторно инициализировать поле типа static final z, потому что конструктор запускается при каждом экземпляре класса, который не должен появляться в статических полях final.

Ответ 2

См:

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

Я не уверен, что ваш конкретный вопрос о пункте 3 (если вы имеете в виду вложенный?). В подробной последовательности указано, что это будет рекурсивный запрос инициализации, чтобы продолжить инициализацию.

Ответ 3

Порядок инициализации:

  • Статические блоки инициализации
  • Блоки инициализации экземпляра
  • Конструкторы

Подробности процесса описаны в документе JVM .

Ответ 4

Статические поля инициализируются, когда класс загружается загрузчиком класса. Значения по умолчанию назначаются в это время. Это делается в порядке, чем в исходном коде.

Ответ 5

статическая переменная

  • Это переменная, которая принадлежит классу, а не объекту (экземпляру)
  • Статические переменные инициализируются только один раз, в начале выполнения (когда Classloader загружает класс в первый раз).
  • Эти переменные сначала инициализируются, прежде чем инициализировать любые переменные экземпляра
  • Единая копия, которая будет использоваться всеми экземплярами класса
  • Статическую переменную можно получить непосредственно по имени класса и не нужен какой-либо объект

Ответ 6

Начиная с кода с другого вопроса:

class MyClass {
  private static MyClass myClass = new MyClass();
  private static final Object obj = new Object();
  public MyClass() {
    System.out.println(obj); // will print null once
  }
}

Ссылка на этот класс начнет инициализацию. Во-первых, класс будет отмечен как инициализированный. Тогда первое статическое поле будет инициализировано новым экземпляром MyClass(). Обратите внимание, что myClass немедленно получает ссылку на пустой экземпляр MyClass. Пространство есть, но все значения равны нулю. Конструктор теперь выполняется и печатает obj, который является нулевым.

Теперь вернемся к инициализации класса: obj сделана ссылка на новый реальный объект, и мы закончили.

Если это было задано с помощью оператора вроде: MyClass mc = new MyClass(); снова выделено пространство для нового экземпляра MyClass (и ссылка помещена в mc). Конструктор снова выполняется и снова печатает obj, который теперь не является нулевым.

Реальный трюк здесь заключается в том, что при использовании new, как и в WhatEverItIs weii = new WhatEverItIs( p1, p2 ); weii, сразу дается ссылка на бит нулевой памяти. Затем JVM начнет инициализировать значения и запустить конструктор. Но если вы каким-то образом ссылаетесь на weii, прежде чем он это сделает, ссылаясь на него из другого потока или, например, ссылаясь на инициализацию класса, вы смотрите экземпляр класса, заполненный нулевыми значениями.

Ответ 7

Статическая переменная может быть инициализирована тремя следующими способами: выберите любой, который вам нравится

  • вы можете ввести его во время объявления
  • или вы можете сделать, сделав статический блок, например: *

    static {       // любой код, необходимый для инициализации, идет здесь   }

*

  1. Существует альтернатива статическим блокам - вы можете написать частный статический метод
class name {
    public static varType myVar = initializeVar();

    private static varType initializeVar() {
        // initialization code goes here
    }
}