Оператор присваивания в Java - Вопросы
Всего: 2 вопросов
1. Как устроен оператор присваивания = в Java и какая у него ассоциативность?
Как устроен оператор присваивания = в Java и какая у него ассоциативность?
Синтаксис: переменная = выражение; — сначала вычисляется правая часть (выражение), затем её значение записывается в переменную слева. Слева обязана стоять изменяемая переменная (l-value), справа — любое выражение совместимого типа.
Оператор = право-ассоциативен: в цепочке a = b = c = 5 он группируется как a = (b = (c = 5)) и выполняется справа налево. При этом само присваивание — это выражение, значением которого является присвоенное значение, поэтому цепочки и работают.
2. Почему b += 5; компилируется, а b = b + 5; — нет, если b имеет тип byte?
byte b = 10;
b += 5; // компилируется
b = b + 5; // ошибка компиляции
Почему b += 5; компилируется, а b = b + 5; — нет, если b имеет тип byte?
byte b = 10;
b += 5; // компилируется
b = b + 5; // ошибка компиляцииДело в неочевидной детали составных операторов присваивания (JLS 15.26.2). Запись E1 op= E2 НЕ эквивалентна E1 = E1 op E2 буквально — на самом деле она равна E1 = (T)((E1) op (E2)), где T — тип левой части. То есть в += уже встроен неявный сужающий каст к типу переменной.
Поэтому b += 5; означает b = (byte)(b + 5); и компилируется без проблем. А в обычном присваивании b = b + 5; такого каста нет: при вычислении b + 5 оба операнда промоутятся до int, и результат типа int нельзя присвоить в byte без явного приведения. Чтобы этот вариант скомпилировался, нужно написать b = (byte)(b + 5);.
Тот же скрытый каст в +=, -=, *= и т.д. может молча обрезать значение при переполнении — об этом легко забыть.