Почему Java + +, - =, * =, / = составные операторы присваивания не требуют приведения? - PullRequest
3492 голосов
/ 03 января 2012

До сегодняшнего дня я думал, что например:

i += j;

Был просто ярлык для:

i = i + j;

Но если мы попробуем это:

int i = 5;
long j = 8;

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

Означает ли это, что на самом деле i += j; является ярлыком для чего-то вроде этого i = (type of i) (i + j)

Ответы [ 11 ]

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

Как всегда с этими вопросами, JLS содержит ответ. В этом случае §15.26.2 Составные операторы присваивания . Выписка:

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

Пример цитируется с §15.26.2

[...] следующий код правильный:

short x = 3;
x += 4.6;

и в результате x имеет значение 7, потому что оно эквивалентно:

short x = 3;
x = (short)(x + 4.6);

Другими словами, ваше предположение верно.

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

Хорошим примером этого кастинга является использование * = или / =

byte b = 10;
b *= 5.7;
System.out.println(b); // prints 57

или

byte b = 100;
b /= 2.5;
System.out.println(b); // prints 40

или

char ch = '0';
ch *= 1.1;
System.out.println(ch); // prints '4'

или

char ch = 'A';
ch *= 1.5;
System.out.println(ch); // prints 'a'
241 голосов
/ 03 января 2012

Очень хороший вопрос. Спецификация языка Java подтверждает ваше предложение.

Например, следующий код является правильным:

short x = 3;
x += 4.6;

и в результате x имеет значение 7, потому чтоэто эквивалентно:

short x = 3;
x = (short)(x + 4.6);
177 голосов
/ 03 января 2012

Да,

в основном, когда мы пишем

i += l; 

компилятор преобразует это в

i = (int)(i + l);

Я только что проверил .class код файла.

Действительно полезно знать

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

вам нужно привести от long к int explicitly в случае i = i + l, тогда он скомпилируется и даст правильный вывод. как

i = i + (int)l;

или

i = (int)((long)i + l); // this is what happens in case of += , dont need (long) casting since upper casting is done implicitly.

, но в случае += это просто отлично работает, потому что оператор неявно выполняет приведение типа от типа правой переменной к типу левой переменной, поэтому нет необходимости явного приведения.

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

Проблема здесь заключается в приведении типов.

Когда вы добавляете int и long,

  1. Объект int преобразуется в long и оба добавляются, и вы получаете объект long.
  2. но длинный объект не может быть неявно приведен к int.Итак, вы должны сделать это явно.

Но += закодирован таким образом, что он выполняет приведение типов.i=(int)(i+m)

51 голосов
/ 23 января 2013

В Java преобразования типов выполняются автоматически, когда тип выражения в правой части операции присваивания можно безопасно преобразовать в тип переменной в левой части присваивания.Таким образом, мы можем безопасно назначить:

byte -> short -> int -> long -> float -> double. 

То же самое не будет работать наоборот.Например, мы не можем автоматически преобразовать long в int, потому что первое требует больше памяти, чем второе, и, следовательно, информация может быть потеряна.Чтобы вызвать такое преобразование, мы должны выполнить явное преобразование.
Тип - Преобразование

43 голосов
/ 02 декабря 2014

Иногда такой вопрос можно задать на собеседовании.

Например, когда вы пишете:

int a = 2;
long b = 3;
a = a + b;

, автоматическое приведение типов отсутствует.В C ++ не будет ошибок при компиляции приведенного выше кода, но в Java вы получите что-то вроде Incompatible type exception.

Так что, чтобы избежать этого, вы должны написать свой код так:

int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting
21 голосов
/ 08 июня 2015

Основное различие заключается в том, что с a = a + b не происходит трансляция типов, и поэтому компилятор злится на вас за то, что вы не типизируете.Но с a += b на самом деле происходит типизация b с типом, совместимым с a.Так что если вы делаете

int a=5;
long b=10;
a+=b;
System.out.println(a);

То, что вы действительно делаете, это:

int a=5;
long b=10;
a=a+(int)b;
System.out.println(a);
11 голосов
/ 18 января 2016

Тонкая точка здесь ...

Существует неявная типизация для i+j, когда j - это двойное число, а i - это целое число.Java ВСЕГДА преобразует целое число в двойное число, когда между ними существует операция.

Чтобы пояснить i+=j, где i - целое число, а j - двойное, можно описатькак

i = <int>(<double>i + j)

См .: это описание неявного приведения

Возможно, для ясности вы можете ввести в этом случае j к (int).

...