почему статический блок не может получить доступ к статической переменной, определенной после нее - PullRequest
3 голосов
/ 19 марта 2019

Я проверил Прямые ссылки во время инициализации поля , и это ответ от @ assylias , но все же я не получил ответа на вопрос , почему .

Почему статический блок может назначать статическую переменную, объявленную после нее, но не может НЕ обращаться к ней?

   class Parent {
        static {
            i = 2; // valid
            // can only assign new value to it instead of accessing it?
//            System.out.println(i); // invalid - compile-error
        }
        static int i = 0;
        static {
            i = 3; // valid
        }
    }

Это связано с тем, что значение еще не инициализировано, поэтому мы просто явно запрещаем вам его использовать? или что-то связано с безопасностью, я не знаю?


обновлен

это не дубликат этой проблемы, которая о

Почему этого не происходит при доступе с именем класса ?

Этот вопрос о том, почему у нас есть этот дизайн? с какой целью?

Ответы [ 2 ]

3 голосов
/ 19 марта 2019

Статические поля инициализируются на основе порядка , они появляются в коде.

Итак, когда вы присваиваете значение переменной i, вы просто говорите компилятору: «ЭйПарень, когда вы добьетесь инициализации этой переменной, установите ее значение в ... ".Но вы не можете использовать до тех пор, пока он не будет инициализирован, потому что он просто еще не существует.

ОБНОВЛЕНИЕ:

Как говорится в книге "Спецификация языка Java "Джеймса Гослинга, Билла Джоя, Гая Стила и Гилада Брача:

Эти ограничения предназначены для перехвата во время компиляции циклических или иным образом искаженных инициализаций.

Учтите это:

static {
            i = 2;
            j = i + 5; //should it be 7 or 15?
}
static int i = 10;
static int j;

Должна ли переменная j быть 7 или 15?Если это 7, то мы дважды инициализировали переменную i, что невозможно, так как поле является статическим.Если это 15, то что означает i = 2;?

Этот код неоднозначен, поэтому спецификация Java не позволяет этого делать.

0 голосов
/ 27 марта 2019

После некоторого дальнейшего прочтения, я думаю, что Павел не совсем точен в этом вопросе, как указано в комментарии @ Holger .

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

Как 12.4.2.Подробная процедура инициализации указывает

Для каждого класса или интерфейса C существует уникальная блокировка инициализации LC .Отображение из C в LC оставлено на усмотрение реализации виртуальной машины Java.

Полагаю, инициализация дважды подходит для самого инициализатора класса, если только один раз для вызывающих клиентов.

Но предоставленные Павлом демо-версии все еще остаются в силе, поэтому я просто использую их здесь, но с другим объяснением.

static {
       i = 2;
       j = i + 5; 
       // no one knows whether "i" here initialized properly here
}
static int i = 10;
static int j;

Но когда вы используете MyClass.i непосредственно в j = MyClass.i + 5, компилятор будет знать, что тогда все будет в порядке как 8.3.3.Прямые ссылки при инициализации поля с четырьмя условиями.

В частности, это ошибка времени компиляции, если all из следующих условий:

  1. Объявление переменной классав классе или интерфейсе C появляется текстуально после использования переменной класса;

  2. Использование - это простое имя в инициализаторе переменной класса C илистатический инициализатор C;

  3. Использование не в левой части присвоения;

  4. C - самый внутренний класс или интерфейс, включающийиспользование.

И в этом ответе уже есть подробное обсуждение.

Чтобы закончить, я думаю, что предсказуемое поведение добавит эти ограничения.Еще раз, другая официальная цель указана в 8.3.3.Прямые ссылки при инициализации поля .

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

...