Использование неинициализированного конечного поля-с / без 'этого.' спецификатор


может кто-нибудь объяснить мне, почему первый из двух образцов компилирует, а второй нет? Обратите внимание, что единственное различие заключается в том, что первый явно квалифицирует ссылку на x с '.этот, а не второй. В обоих случаях, окончательное поле X явно пытался быть использованы до инициализации.

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

1)

public class Foo {
    private final int x;
    private Foo() {
        int y = 2 * this.x;
        x = 5;
    }
}

2)

public class Foo {
    private final int x;
    private Foo() {
        int y = 2 * x;
        x = 5;
    }
}
4 53

4 ответа:

после того, как куча spec-чтения и мысли, я пришел к выводу, что:

в компиляторе Java 5 или Java 6 это правильное поведение. Глава 16 "определенное задание Спецификация Языка Java, Третье Издание говорит:

каждая локальная переменная (§14.4) и каждый пробел final(§4.12.4) поле (§8.3.1.2) должен быть наверняка назначена значение когда происходит какой-либо доступ к его значению. Доступ к его значению состоит из простое имя переменной встречается в любом месте выражения, за исключением левого операнда простого оператора присваивания =.

(выделено мной). Так что в выражении 2 * this.x на this.x часть не считается "доступа [x's] значение" (и поэтому не подчиняется правилам определенного присвоения), потому что this.x - это не простое имя переменной экземпляра x. (N. B. правило для случаев, когда происходит определенное назначение, в абзаце после приведенного выше текста,тут разрешить что-то вроде this.x = 3, и считает x чтобы быть определенно назначен после этого; это только правило для доступа, который не считается this.x.) Обратите внимание, что значение this.x в этом случае будет ноль, за §17.5.2.

в компиляторе Java 7 это ошибка компилятора, но понятная один. Глава 16 "определенное назначение"Спецификация Языка Java, Java 7 SE Edition говорит:

каждая локальная переменная (§14.4) и каждый пробел

при использовании this в конструкторе, компилятор видитx как атрибут членом thisобъект (по умолчанию инициализирован). Так как x и int, это по умолчанию инициализируется с 0. Это делает компилятор счастливым и его работа хорошо во время выполнения тоже.

когда вы не используете this, то компилятор использует x объявление непосредственно в лексическом анализе и, следовательно, он жалуется на его инициализацию (явление времени компиляции).

так это определение this, Что делает компилятор для анализа x как переменная-член объекта по сравнению с прямым атрибутом во время лексического анализа в компиляции и приводит к различному поведению компиляции.

при использовании в качестве основного выражения ключевое слово this обозначает значение, которое является ссылкой на объект, для которого был вызван метод экземпляра (§15.12), или на объект строится.

Я думаю, что компилятор оценивает, что писать это.x подразумевает, что " это " существует, поэтому был вызван конструктор (и конечная переменная была инициализирована). Но вы должны получить RuntimeException при попытке запустить его

Я предполагаю, что вы имеете в виду поведение в Eclipse. (Как указано в комментарии компиляция с javac работает).

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