Почему я + = l компилирую, где я int, а l long? - PullRequest
8 голосов
/ 03 января 2012

Я заметил Java + +, - =, * =, / = составные операторы присваивания (хороший вопрос :)), но в нем была часть, которую я не совсем понимаю. Заимствуя из этого вопроса:

int i = 5;
long l = 8;

Тогда i = i + l; не скомпилируется, но i += l; скомпилируется нормально.

Принятый ответ на связанный вопрос гласит:

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

, что означает, что i += l; совпадает с i = (int)((i) + (l));, за исключением того, что i оценивается только один раз.

A long может быть (IIRC даже гарантированно будет) длиннее int и, следовательно, может содержать гораздо больший диапазон значений.

Учитывая, что эта ситуация может очень легко привести к потере данных из-за необходимого сужающего преобразования в некоторый момент во время выполнения оператора (или оценка выражения r-значения, или присваивание), почему i += l; не является ошибкой времени компиляции или хотя бы предупреждение?

Ответы [ 3 ]

14 голосов
/ 03 января 2012

В основном, потому что i += l скомпилирован так, как если бы он был написан i = (int) (i + l). При добавлении int значений к byte и char переменным возникают похожие «сюрпризы» - оператор присваивания работает, а простой оператор сложения - нет.

8 голосов
/ 16 февраля 2012

Учитывая, что эта ситуация может очень легко привести к потере данных из-за необходимого сужающего преобразования в какой-то момент во время выполнения оператора (либо оценка выражения r-значения, либо присвоение), почему i + = l;не ошибка времени компиляции или хотя бы предупреждение?

Это, вероятно, должно быть, как вы сказали, либо ошибка времени компиляции, либо хотя бы предупреждение.Большинство книг и учебных пособий, которые мне известны, представляют x += y; как сокращение для x = x + y;.Я, честно говоря, не знаю ни одного, которое делает различие, обозначенное в разделе 15.26.2 Составных операторов присваивания JLS, кроме одного.

В главе 2 (загадка 9) из Java Puzzlers: ловушки, ловушки и угловые случаи авторы (Джошуа Блох и Нил Гафтер) просят вас предоставить объявления для x и i, чтобы это было юридическое утверждение:

x += i;

и это не так:

x = x + i;

Существует множество решений, включая первые две строки кода, которые вы разместили в своем вопросе.Авторы предостерегают от использования составных операторов присваивания для переменных типов byte, short и char и рекомендуют при использовании этих операторов для переменных типа int проверять, что выражение RHS не являетсяlong, float или double.

Они завершаются следующим наблюдением (выделено мое):

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

1 голос
/ 16 февраля 2012

причина этого в том, что вы можете сделать:

byte b = 1;

b += 1;

если + = был расширен до b = b + 1, то выражение не будет проверять тип, потому что выражение "b + 1" имеет тип int. все целочисленные выражения в java имеют по крайней мере тип int, даже если вы добавляете два байта вместе.

public class Test {
  public static void main(String[] args) {
    byte b = 1;
    byte c = 2;
    byte d = b + c;
  }
}


Test.java:5: possible loss of precision
found   : int
required: byte
    byte d = b + c;
               ^
1 error
...