До сегодняшнего дня я думал, что, например:
i += j;
Был просто ярлык для:
i = i + j;
Но если мы попробуем это:
int i = 5;
long j = 8;
Тогда i = я + j;
не будет компилироваться, но i += j;
будет компилировать штраф.
Означает ли это, что на самом деле i += j;
является ярлыком для чего-то вроде этого i = (type of i) (i + j)
?
Как всегда с этими вопросами, 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);
Другими словами, ваше предположение верно.
i+=j
компилирую, как я проверял сам, но это приведет к потере точности, верно? Если это так, то почему это не происходит и в i = i + j? Зачем нас там пугать?
i += j
) безопаснее предположить, что потеря точности желательна в отличие от другого случая ( i = i + j
)
Хорошим примером этой отливки является использование * = или /=
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'
Очень хороший вопрос. Спецификация Java Language подтверждает ваше предложение.
Например, следующий код верен:
short x = 3; x += 4.6;
и приводит к тому, что x имеет значение 7, потому что оно эквивалентно:
short x = 3; x = (short)(x + 4.6);
Да,
в основном, когда мы пишем
i += l;
компилятор преобразует это значение в
i = (int)(i + l);
Я только что проверил код файла .class
.
Действительно хорошая вещь, чтобы знать
вам нужно сделать от 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.
но в случае +=
он просто отлично работает, потому что оператор неявно выполняет литье типов из типа правой переменной в тип левой переменной, поэтому не нужно явно указывать.
int
выполняется после +
. Компилятор (должен?) Выдать предупреждение, если он действительно приведёт long
к int
.
Проблема здесь связана с литьем типов.
Когда вы добавляете int и long,
Но +=
закодирован таким образом, что он набирает тип. i=(int)(i+m)
В преобразованиях типа Java выполняется автоматически, когда тип выражения в правой части операции присваивания можно безопасно продвигать к типу переменной в левой части задания. Таким образом, мы можем смело назначить:
byte -> short -> int -> long -> float -> double.
То же самое не будет работать наоборот. Например, мы не можем автоматически преобразовать long в int, потому что первое требует большего объема памяти, чем второе, и, следовательно, информация может быть потеряна. Чтобы заставить такое преобразование, мы должны выполнить явное преобразование.
Тип - Конверсия
long
в 2 раза больше, чем float
.
float
не может содержать все возможные значения типа int
, а double
не может содержать все возможные значения типа long
.
Иногда такой вопрос можно задать на собеседовании.
Например, когда вы пишете:
int a = 2;
long b = 3;
a = a + b;
нет автоматического приведения типов. В С++ не будет никакой ошибки компиляции вышеуказанного кода, но в Java вы получите что-то вроде Incompatible type exception
.
Чтобы избежать этого, вы должны написать свой код следующим образом:
int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting
op
в C ++ с его использованием в Java. Мне всегда нравится видеть эти мелочи, и я думаю, что они вносят свой вклад в разговор, который часто может быть пропущен.
Основное отличие состоит в том, что с 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
для i+j
когда j
является double, а i
- int. Java ALWAYS преобразует целое число в double при выполнении операции между ними.
Чтобы прояснить i+=j
где i
- целое число, а j
- двойное, можно описать как
i = <int>(<double>i + j)
См. Это описание неявного литья
В этом случае вам может потребоваться приведение типа j
к (int)
для ясности.
int someInt = 16777217; float someFloat = 0.0f; someInt += someFloat;
, Добавление нуля к someInt
не должно влиять на его значение, но продвижение someInt
для float
может изменить его значение.
В случае оператора оператора присваивания выполняется автоматический запуск внутреннего типа:
byte b1 = 10;
//b1 = b1 + 1; Compile time error because found int
System.out.println(b1);
byte b3 = 10;
b3 += 1; //in compound assignment implicit type casting will be performed simultaneously
System.out.println("b3=: "+b3);
byte b4 = 127;
b4 += 3; //in compound assignment implicit type casting will be performed simultaneously
System.out.println("b4=: "+b4);//-126
И в некоторых случаях вы потеряете некоторые значения:
int i = 1;
i += 1.5;
System.out.println("i=: "+i); //will print 2, and you lost .5 !!!