Почему не Java +=, -=, *=, /= составные операторы назначения требуют литья?

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

i += j;

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

i = i + j;

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

int i = 5;
long j = 8;

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

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

10 ответов


как всегда с этими вопросами, 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);

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


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

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'

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

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

short x = 3;
x += 4.6;

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

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

Да

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

i += l; 

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

i = (int)(i + l);

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

действительно хорошая вещь, чтобы знать


вам нужно бросить из long to 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.

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


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

при добавлении int и long,

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

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


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

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

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


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

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

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

главное отличие в том, что с 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);

тонкий момент здесь...

существует неявная типизация для i+j, когда j двойной и i является int. Java всегда преобразует целое число в double, когда между ними есть операция.

разъяснить i+=j здесь i - это целое число, а j двойник можно описать как

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

посмотреть: это описание неявного кастинга

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