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

Почему переменная инициализация выражения присваивания [String x = (x = y)] компилируется?

Как это компилируется без ошибок? Как я понимаю, компилятор проверяет тип переменной (в данном случае String), а затем видит, соответствует ли тип выражения с правой стороны типу переменной (или, по крайней мере, подтипу, но позволяет придерживаться простого case с классом String, так как он окончательный).

public class InitClass {
  public static void main(String[] args) {
    String str = (str = "hello");
    System.out.println(str);
  }
}

Мой вопрос: как скомпилировать str = "hello"? Компилятор уже знает, что str должен иметь тип String?

4b9b3361

Ответ 1

При оценке выражения

Сначала левый операнд оценивается для создания переменной. Если эта оценка завершается внезапно, тогда выражение присваивания внезапно завершается по той же причине; правый операнд не оценивается и не выполняется присвоение.

Это создает переменную str. Тогда

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

В вашем примере правый операнд сам по себе является другим выражением присваивания. Итак, str, правый операнд оператора присваивания, снова вычисляется для создания переменной str. Тогда

В противном случае значение правого операнда преобразуется в тип левой переменной, подвергается преобразованию значений (П. 5.1.13) до соответствующего стандартного значения (не , а результат преобразования - хранится в переменной.

Итак "hello" сохраняется в str. А так как

Во время выполнения результатом выражения присваивания является значение переменная после назначения. Результат выражение присваивания не является самой переменной.

результатом присвоения "hello" - str является значение "hello", это значение снова сохраняется в str.

Ответ 2

Ваш случай эквивалентен

String str;
str = (str = "hello");

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

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

Локальная переменная имеет более строгие требования (чем полевая переменная) - она ​​должна быть назначена первой до использования ее значения. Например, это не будет компилироваться, потому что локальный var читается до его назначения.

String str;  // local variable
str = str;   // error, try to read `str` before it assigned

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

int x = x+1;  // error. x is field variable.

Но это не катастрофично, если такая проверка завершилась неудачно, поскольку x имеет значение 0 перед явным назначением

int x;
{ x=x+1; } // ok. x==0, then x==1 after assignment

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

final int x = (this).x+1;  // compiles!

В некоторых случаях компилятор выходит за борт, предотвращая использование допустимых случаев использования лямбда

Runnable r1 = ()->System.out.println(r1);  // r1 is a field variable 

Нет ничего концептуально проблематичного в этом случае; его можно обойти и с помощью (this)..

Ответ 3

Что первое происходит, так это то, что компилятор идентифицирует тип ссылки, а затем зная, что это строка, которую присваивает "привет" на str.