Arhn - архитектура программирования

Порядок инициализации статического конечного поля Java

Я попытался понять поведение порядка инициализации, когда статические поля инициализируются ссылкой на один и тот же объект окружающего класса.

public class Test {

        static final Test t=new Test();
        static int a=5;

        Test(){
            System.out.println("a="+a);
        }

        public static void main(String[] args) {
            new Test();
        }

    }

Вывод приведенного выше фрагмента кода:

a=0
a=5

Если я изменю переменную a на что-нибудь другое, кроме простого static:

static final a=5;
a=5;
final a=5;

Результат:

a=5
a=5

Почему такое поведение?

Обратите внимание, что вывод равен a=5 & a=5, даже если оба t & a объявлены как static final, и в этом случае t предшествует объявлению a.


Ответы:


1

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

не окончательные статические элементы инициализируются в порядке появления

Поэтому в вашем первом случае:

    static Test t=new Test();
    static int a=5;

Конструктор сначала вызывается перед инициализацией a, поэтому отображается a=0.

Во втором случае static final a инициализируется перед t, поэтому a=5 отображается при создании первого экземпляра Test. Когда a не является статическим, он инициализируется до выполнения конструктора, поэтому снова отображается a=5.

Что касается редактирования в вашем вопросе.

Глядя на раздел 12.4.2 JLS :

  1. Затем инициализируйте окончательные переменные класса и поля интерфейсов, значениями которых являются постоянные выражения времени компиляции (§8.3.2.1, §9.3.1, §13.4.9, §15.28).

...

  1. Затем выполните либо инициализаторы переменных класса и статические инициализаторы класса, либо инициализаторы полей интерфейса в текстовом порядке, как если бы они были одним блоком.

Вы видите, что переменные класса final (т. е. static final) инициализируются перед остальными статическими переменными, только если их значения являются временем компиляции постоянные выражения. 5 — постоянное выражение. new Test() нет. Поэтому a инициализируется до t, даже если оба являются статическими final.

09.01.2015
  • Спасибо! Но t также должен быть инициализирован перед выполнением конструктора? Разве это не похоже на циклическую зависимость? Есть ли определенное поведение, когда Java сталкивается с циклическими зависимостями...? 09.01.2015
  • @ernesto Инициализация t приводит к созданию нового экземпляра. Когда создается новый экземпляр, выполняется конструктор. Операторы инициализации переменных экземпляра выполняются до выполнения конструктора. Поэтому, когда a не является статическим, он инициализируется значением 5 перед оператором println. 09.01.2015
  • Я обновил вопрос. Выход a=5 & a-5, даже если t объявлен как static final, что предшествует объявлению a 11.01.2015

  • 2

    Статические переменные инициализируются, когда класс загружается загрузчиком классов. Итак, когда первая строка «static Test t=new Test();» выполняется, значение int «a» еще не инициализировано, поэтому оно отображается как 0. Но в других 3 случаях (т. е. удаление статики, добавление final или без какого-либо модификатора) происходит инициализация во время создания объекта Тестовый класс, который происходит в первой строке, поэтому показывает значение «5».

    09.01.2015

    3

    Спецификация языка Java это лучший источник, чтобы понять все о порядке инициализации. В соответствии с этим в вашем сценарии поле static final инициализируется до инициализации любой переменной уровня класса. При удалении финала инициализация откладывалась. Следует также отметить, если вы измените

    static Test t=new Test();
    static int a=5;
    

    to

      static int a=5;
      static Test t=new Test();
    

    он также будет печатать

     a = 5
     a = 5
    

    из-за порядка инициализации.

    09.01.2015
  • где в этой спецификации они сказали, что static final будет инициализирован прежде всего? 09.01.2015
  • Итак, пункт 6 указывает, что final переменные будут инициализированы до static. Допустим, у меня в классе есть переменные static, final и static final, каков порядок? 09.01.2015
  • Почти уверен, что это статический финал, затем статический, затем финальный, затем нефинальный. Внутри каждой группы порядок сверху вниз. 09.01.2015
  • final переменные со значениями не могут быть изменены в любой момент времени, потому что они являются постоянными выражениями времени компиляции. Таким образом, конечные переменные, независимо от уровня класса или экземпляра, инициализируются на одном уровне. Когда дело доходит до пустых финалов, ваш порядок инициализации отличается (инициализация финальных переменных может быть отложена до конца блоков инициализатора), т.е. сначала статический, а затем уровень экземпляра. Как константные выражения, вы не можете видеть, что происходит первым, потому что они следуют текстовому порядку. 09.01.2015
  • Я обновил вопрос. Выход a=5 & a-5, даже если t объявлен как static final, что предшествует объявлению a 11.01.2015

  • 4

    static final a=5 Это final, поэтому он инициализируется первым, перед другими статическими членами или методами.

    В первом сценарии метод main() выполняется первым, и он инициализируетa своим значением по умолчанию 0.

    09.01.2015
    Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..