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

StackOverflow https://stackoverflow.com/questions/3699010

Вопрос

public class Main {

    static int x = Main.y;
//  static int x = y; //Not allowed; y is not defined
    static int y = x;
    public static void main(String[] args) {
        System.out.println(x);//prints 0
    }
}

Как мне позволено использовать в классе, но не напрямую?

Когда определяется у?

Это было полезно?

Решение

Точные правила, регулирующие пересылки на переменные класса, описаны в разделе §8.3.2.3 jls:

8.3.2.3 Ограничения на использование полей при инициализации

Декларация члена должно появиться текстовым, прежде чем он используется только в том случае, если член является экземпляром (соответственно static) Поле класса или интерфейса C и все следующие условия удержания:

  • Использование происходит в экземпляре (соответственно static) переменная инициализатор C или в экземпляре (соответственно static) инициализатор C.
  • Использование не на левой стороне задания.
  • Использование - это простое имя.
  • C - самый внутренний класс или интерфейс, охватывающий использование.

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

Это означает, что ошибка времени компиляции результаты из программы тестирования:

  class Test {
      int i = j;  // compile-time error: incorrect forward reference
      int j = 1;
  }

В то время как следующий пример компилирует без ошибки:

  class Test {
      Test() { k = 2; }
      int j = 1;
      int i = j;
      int k;
  }

Хотя конструктор (§8.8) Для теста относится к области k, который объявлен три строки позже.

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

class Z {
  static int i = j + 2; 
  static int j = 4;
}

и:

class Z {
  static { i = j + 2; }
  static int i, j;
  static { j = 4; }
}

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

class Z {
  static int peek() { return j; }
  static int i = peek();
  static int j = 1;
}
class Test {
  public static void main(String[] args) {
      System.out.println(Z.i);
  }
}

производит выход:

0

Поскольку инициализатор переменных для I использует метод класса PEEK для доступа к значению переменной j, прежде чем j был инициализирован его переменным инициализатором, в какой момент он все еще имеет значение по умолчанию (§4.12.5).

Другие советы

Я бы предположим, что, используя класс, компилятор отложит поиск переменной до тех пор, пока класс не был завершен, поэтому он находит Y, но если вы просто определите его, как комментарий, он еще не определен, поэтому он не соответствует

Статические переменные определяются в порядке декларации в классе, во время нагрузки класса. Когда JVM загрузит Main класс, x будет определен, то y. Отказ Вот почему вы не можете напрямую использовать y при инициализации x, Вы создаете что-то, что называется Передовая ссылка, вы относитесь к переменной, которая в настоящее время не определена, и это незаконно для компилятора.

Когда используешь Main.y, Я думаю, что происходит следующее:

  • Вы загружаете Main, x Инициализация называется
  • Когда вы определяете x быть равным Main.y, Компилятор видит ссылку на класс, поэтому он закончится определение x к текущей стоимости участника y класса Main. Отказ Это относится к этому делу, как будто Main был другим классом.

Обратите внимание, что в этом случае при инициализации x, y не был определен на данный момент. Так x будет иметь значение 0.

Вам не разрешено делать это, потому что это бессмысленно. Единственная возможная интерпретация в том, что у Инициализируется до нуля, и у вас уже есть два способа сказать это. Вам не нужно это.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top