Внутренняя обработка статических и нестатических прямых ссылок в Java

Я работаю с прямыми ссылками в Java и задаюсь вопросом, почему Java позволяет прямую ссылку с ClassName (в статической переменной) или с this ссылка в случае переменной экземпляра? Каков фоновый процесс, который происходит на уровне JVM? Например:

Статическая прямая ссылка

class StaticForwardReferences {
    static {
        sf1 = 10;   // (1)
        int b = sf1 = 20;   // (2)
        int c = StaticForwardReferences.sf1; // (3) Works fine
        // Above statement allows the allocation of value of 'sf1'
        // to variable 'c' just because it is accessed with class name
        // instead of direct name

        // whereas below statement throws illegal forward reference
        // error at compile time
        System.out.println(sf1); // (4) Illegal forward reference
    }
    static int sf1 = sf2 = 30;
    static int sf2;

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

Есть ли какое-либо временное хранилище, где значения сохраняются, когда мы делаем прямую ссылку, назначая переменные перед их объявлением, как это сделано в шагах (1) и (2) выше, если мы печатаем значение переменной c, он показывает значение из самого последнего присвоения sf1,

Нестатическая прямая ссылка

class NonStaticForwardReferences {
    {
        nsf1 = 10;
        System.out.println(this.nsf1);  // 10
        nsf1 = sf1;
        // System.out.println(nsf1); Illegal forward reference
        int b = nsf1 = 20;

        int c = this.nsf1;
        System.out.println(c);  // 20
        // why variable 'c' is initialized to 20 when used with 'this' reference
        // instead of showing illegal forward reference, how it works in the background?
   }

   int nsf1 = nsf2 = 30;
   int nsf2;
   static int sf1 = 5;

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

Пожалуйста, осветите фоновый процесс, который происходит за кулисами в двух вышеупомянутых случаях. Заранее спасибо!:)

3 ответа

JLS, раздел 8.3.3, устанавливает условия для прямой ссылки на статическую переменную ("переменную класса") ошибки компилятора, хотя и не указывает причины.

Использование переменных класса, объявления которых появляются в текстовом виде после использования, иногда ограничено, даже если эти переменные класса находятся в области видимости (§6.3). В частности, это ошибка времени компиляции, если выполняются все следующие условия:

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

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

  • Использование не на левой стороне задания;

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

(курсив выделен мной)

Ошибка прямой ссылки на переменные экземпляра появляется при следующих условиях:

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

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

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

  • Использование не на левой стороне задания;

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

(курсив выделен мной)

В обоих случаях использование простого имени является ключевым условием. Это означает использование переменной без какого-либо спецификатора, такого как this или имя класса. Вот почему this.nsf1 работает в NonStaticForwardReferences, Если вы удалите this, то ошибка происходит. Это также почему sf1 имеет ошибку и StaticForwardReferences.sf1; не имеет ошибки.

Запрет на прямые ссылки не подразумевает, что переменные создаются при инициализации. "Фоновый процесс" состоит в том, что классы и объекты размещаются одновременно, а (статическим) переменным присваиваются значения по умолчанию. (Что означает "ноль": это, вероятно, реализовано с calloc или же memset на практике.)

Правила прямой ссылки предназначены для предотвращения просмотра этих первых значений, особенно для final переменные, которые предположительно когда-либо имеют только одно значение. Но они существуют, чтобы улавливать человеческие ошибки и сами по себе не идеальны: только для постоянных переменных инициализация происходит так рано, что значения по умолчанию ненаблюдаемы. Определение this или имя класса явно является самым простым способом демонстрации этого эффекта.

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

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

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

Другие вопросы по тегам