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

Использование this.var во время инициализации var

При исследовании еще одного вопроса я с удивлением обнаружил, что следующий код Java компилируется без ошибок:

public class Clazz {
    int var = this.var + 1;
}

В моем JDK6 var инициализируется до 1.

Является ли приведенный выше код хорошо определенной семантикой или его поведение undefined? Если вы говорите это четко, процитируйте соответствующие части JLS.

4b9b3361

Ответ 1

Об этом говорится в примере 8.3.2.3-1 в разделе раздел 8.3.2.3. В тексте к примеру

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);
    }
}

заголовок говорит:

... инициализатор переменной для я использует метод peek метода для доступа к значению переменной j до того, как j был инициализирован его инициализатором переменной, после чего он по-прежнему имеет значение по умолчанию (§4.12. 5).

Это должно отображаться непосредственно в вашей ситуации.

Ответ 2

Глава 8.3.2.2. пункт 2:

В выражениях инициализации для переменных экземпляра разрешено ссылаться на текущий объект (§15.8.3) и использовать ключевое слово super (§15.11.2, §15.12).

В следующем абзаце добавляется:

Использование переменных экземпляра, объявления которых появляются по тексту после использования, иногда ограничены, хотя эти переменные экземпляра находятся в области видимости. См. Раздел 8.3.3.3 для точных правил, регулирующих прямую ссылку на переменные экземпляра.

Ответ 3

Введение главы 16

В главе 16 описывается точный способ обеспечения языка что локальные переменные определенно установлены перед использованием. Хотя все остальные переменные автоматически инициализируются значением по умолчанию, Java язык программирования не автоматически инициализирует локальные переменные чтобы избежать маскировки ошибок программирования.

Ответ 4

Использование простого имени не допускается в случае forward references согласно JSL. Поэтому для доступа к таким переменным необходимо использовать this.

class UseBeforeDeclaration {
    int h = j++;  // error - `j` read before declaration
    int l = this.j * 3;  // ok - not accessed via simple name
    int j;
}

Ответ 5

Так как всем нелокальным переменным присваивается начальное значение (а назначение выполняется - перед всем остальным), нет никаких проблем с их чтением в любое время.

Спектр выборочно запрещает некоторые обращения в некоторых ситуациях, полагая, что такие обращения, скорее всего, являются ошибками программирования. Но если бы они были разрешены, у них была бы четко определенная семантика.

На самом деле программист может легко обойти ограничения и "косвенно" получить доступ к полю в любом случае; семантика этого доступа совпадает с "прямым" доступом, если это разрешено.

int var = this.var + 1;       // suppose javac forbids this

int var = this.getVar() + 1;  // but can javac forbid this?

Ответ 6

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

обратитесь к главе 4.12.3 Виды переменных из http://docs.oracle.com/javase/specs/jls/se7/jls7.pdf (стр. 80). Пример также приведен здесь.

      **Example 4.12.3-1. Different Kinds of Variables**
      class Point { 
      static int numPoints; // numPoints is a class variable 
      int x, y; // x and y are instance variables 
      int[] w = new int[10]; // w[0] is an array component 
      int setX(int x) { // x is a method parameter 
        int oldx = this.x; // oldx is a local variable 
        this.x = x; 
        return oldx; 
      } 
    }