Это потому, что b += 1.0;
эквивалентно b = (int) ((b) + (1.0));
. сужающее примитивное преобразование (JLS 5.1.3) скрыто в составной операции присваивания.
Составное выражение присваивания в форме E1 op = E2 эквивалентно E1 = (T) ((E1) op (E2)) , где T является типом E1 , за исключением того, что E1 оценивается только один раз.
Например, следующий код является правильным:
short x = 3;
x += 4.6;
и в результате x
будет иметь значение 7
, поскольку оно эквивалентно:
short x = 3;
x = (short)(x + 4.6);
Это также объясняет, почему компилируется следующий код:
byte b = 1;
int x = 5;
b += x; // compiles fine!
Но это не так:
byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!
В этом случае вам необходимо явно привести:
byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!
Стоит отметить, что неявное приведение в составномзадания - предмет Головоломка 9: Твидледум из замечательной книги Java Puzzlers .Вот некоторые выдержки из книги (слегка отредактированные для краткости):
Многие программисты считают, что x += i;
- это просто сокращение для x = x + i;
.Это не совсем верно: если тип результата шире, чем у переменной, составной оператор присваивания выполняет тихое сужающее примитивное преобразование.
Чтобы избежать неприятных сюрпризов, не использует составноеоператоры присваивания переменных типа byte
, short
или char
.При использовании составных операторов присваивания для переменных типа int
убедитесь, что выражение справа не имеет типа long
, float
или double
.При использовании составных операторов присваивания для переменных типа float
убедитесь, что выражение в правой части не имеет типа double
.Эти правила достаточны для того, чтобы компилятор не генерировал опасные сужающие приведения.
Для разработчиков языков, вероятно, ошибочно для составных операторов присваивания создавать невидимые приведения;составные присваивания, в которых переменная имеет более узкий тип, чем результат вычисления, вероятно, должны быть недопустимыми.
Последний абзац стоит отметить: C # намного более строг в этом отношении (см. Спецификация языка C # 7.13.2 Составное присваивание ).