Почему составное присваивание в Java не устраняет проблемы переполнения?

StackOverflow https://stackoverflow.com/questions/5480873

Вопрос

К моему шоку, оказалось, что следующий код скомпилируется даже без предупреждений:

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value += increment;
}

Хотя это дает ошибку времени компиляции, как и следовало ожидать:

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value = value + increment;
}

Я проверил это, и действительно, JLS (раздел 15.26.2) говорит следующее:

Выражение составного назначения формы e1 op = e2 эквивалентно e1 = (t) ((e1) op (e2)), где t - тип E1, за исключением того, что E1 оценивается только один раз.

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

Это было полезно?

Решение

Здесь одинОбъяснение:

Когда вы делаете задание (фрагмент первого кода), проверка типа Java Enforce, потому что LHS и RHS могут быть вполне могут быть независимыми друг от друга.

Но соединение-оператор больше похоже на инкрементный оператор.+= Изменяет значение переменной участвует, а не назначать новый Значение для переменной.Когда вы измените байт, вы ожидаете байта как результат.Сделать жизнь проще, Java делает неявное преобразование типа для составные операторы, потому что они модификаторы.

Другие советы

Составные операторы присваивания определяются JLS (15.26.2) следующее:

«Выражение составного присваивания вида E1 op= E2 эквивалентно

      E1 = (T)((E1) op (E2))`, 

где T — тип E1, за исключением того, что E1 оценивается только один раз».

В этом случае E1 имеет тип int E2 имеет тип long, и оп +.Итак, это эквивалентно:

value = (int)(value + increment);

Добавление int и long дает long который затем возвращается в int перед назначением.Все в порядке, следовательно, ошибок компиляции нет.

Разница между этим и простым присваиванием (т.е. value = value + increment;), заключается в том, что простое присваивание не имеет приведения типа.


Итак почему они так это определили?

Я думаю, что причина в том, чтобы сделать такие примеры:

    byte b = ...
    b += 1;

Без приведения типов, b += 1 это будет ошибка компиляции, и вам нужно будет написать ее так:

    b += (byte) 1;

Эта ссылка проанализировала проблему, которую вы вызваны.

Разное поведение для возможной потери точности

Чтобы избежать неприятных сюрпризов, не делайте Используйте комбинированные операторы назначения на Переменные типа байта, короткие или Char.При использовании составного назначения Операторы по переменным типа INT, Убедитесь, что выражение на правая сторона не имеет большого типа, поплавок или двойной.При использовании соединения Операторы назначения на переменные Тип поплавок, убедитесь, что выражение на правой стороне не типа двойной.Эти правила достаточно для предотвратить создание компилятора опасные суженные каскися.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top