статические - типы данных java
Почему инициализация переменной для выражения присваивания[String x=(x=y)] компилируется? (2)
Как это компилируется без ошибок? Насколько я понимаю, компилятор проверяет тип переменной (в данном случае String
), а затем проверяет, соответствует ли тип выражения в правой части типу переменной (или хотя бы подтипу, но давайте придерживаться простого случая с класс String
поскольку он окончательный).
public class InitClass {
public static void main(String[] args) {
String str = (str = "hello");
System.out.println(str);
}
}
Мой вопрос: как компилируется str = "hello"
? Компилятор уже знает, что str
должен иметь тип String
?
Ваш случай эквивалентен
String str;
str = (str = "hello");
Хотя задания выглядят смешно, концептуально нет ничего плохого.
Тем не менее, инициализация переменной, которая ссылается на себя, явно не очень хорошая идея. Компилятор попытается пометить его в ситуациях, которые, скорее всего, являются ошибкой программиста; компилятор не может сделать это несколько раз; и может также пойти за борт в другое время.
Локальная переменная имеет более строгое требование (чем полевая переменная) - она должна быть назначена первой перед использованием ее значения. Например, это не скомпилируется, потому что локальная переменная читается перед назначением.
String str; // local variable
str = str; // error, try to read `str` before it's 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).
тоже.
При оценке выражения присваивания
Во-первых, левый операнд вычисляется для создания переменной. Если эта оценка завершается преждевременно, то выражение присваивания завершается преждевременно по той же причине; правый операнд не оценивается и присваивания не происходит.
Это производит переменную str
. затем
В противном случае вычисляется правый операнд . Если эта оценка завершается преждевременно, то выражение присваивания завершается преждевременно по той же причине, и назначение не происходит.
В вашем примере правый операнд сам по себе является другим выражением присваивания. Таким образом, str
, правый операнд оператора присваивания, снова вычисляется для получения переменной str
. затем
В противном случае значение правого операнда преобразуется в тип левой переменной, подвергается преобразованию набора значений (§5.1.13) в соответствующий набор стандартных значений (не набор значений с расширенным показателем), и результат преобразования сохраняется в переменной.
Так что "hello"
хранится в str
. И с тех пор
Во время выполнения результатом выражения присваивания является значение переменной после присвоения. Результат выражения присваивания сам по себе не является переменной.
Результатом присвоения "hello"
str
является значение "hello"
, это значение снова сохраняется в str
.