¿Por qué los operadores de asignación compuesta +=, -=, *=, /= de Java no requieren convertir long to int?

8 minutos de lectura

Avatar de usuario de Honza Brabec
Honza Brabec

Hasta hoy, pensé que por ejemplo:

i += j;

Era solo un atajo para:

i = i + j;

Pero si probamos esto:

int i = 5;
long j = 8;

Entonces i = i + j; no compilará pero i += j; compilará bien.

¿Significa que de hecho i += j; es un atajo para algo como esto
i = (type of i) (i + j)?

  • Me sorprende que Java permita esto, siendo un lenguaje más estricto que sus predecesores. Los errores en la conversión pueden provocar fallas críticas, como fue el caso del vuelo 501 de Ariane5, donde una conversión flotante de 64 bits a un entero de 16 bits resultó en el bloqueo.

    – SQLDiver

    5 de enero de 2015 a las 16:31


  • En un sistema de control de vuelo escrito en Java, esta sería la menor de sus preocupaciones @SQLDiver

    – Ross Drew

    2 de noviembre de 2015 a las 9:24

  • De hecho i+=(long)j; incluso se compilará bien.

    – Tharindu Sathischandra

    18 de marzo de 2016 a las 7:45

  • El impulso constante de un conjunto de desarrolladores por la precisión y otro por la facilidad de uso es realmente interesante. Casi necesitamos dos versiones del lenguaje, una que sea asombrosamente precisa y otra que sea fácil de usar. Empujar a Java desde ambas direcciones hace que no sea adecuado para ninguno de los dos grupos.

    – Bill K.

    19 de septiembre de 2017 a las 16:03


  • si requiriera casting, ¿dónde lo pondrías? i += (int) f; arroja f antes de la suma, por lo que no es equivalente. (int) i += f; arroja el resultado después de la asignación, tampoco es equivalente. no habría lugar para colocar una conversión que significaría que desea convertir el valor después de agregar, pero antes de la asignación.

    – Tempestad de Norill

    24 de octubre de 2018 a las 13:09

Avatar de usuario de Lukas Eder
lukas eder

Como siempre con estas preguntas, el JLS tiene la respuesta. En este caso §15.26.2 Operadores de asignación compuesta. Un extracto:

Una expresión de asignación compuesta de la forma E1 op= E2 es equivalente a E1 = (T)((E1) op (E2))dónde T es el tipo de E1excepto eso E1 se evalúa una sola vez.

Un ejemplo citado de §15.26.2

[…] el siguiente código es correcto:

short x = 3;
x += 4.6;

y da como resultado que x tenga el valor 7 porque es equivalente a:

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

En otras palabras, su suposición es correcta.

  • Entonces i+=j compila como lo verifiqué yo mismo, pero resultaría en una pérdida de precisión, ¿verdad? Si ese es el caso, ¿por qué no permite que suceda también en i=i+j? ¿Por qué molestarnos allí?

    – bad_keypoints

    22 de septiembre de 2012 a las 6:07

  • @ronnieaka: Supongo que los diseñadores de lenguaje sintieron que en un caso (i += j), es más seguro asumir que se desea la pérdida de precisión a diferencia del otro caso (i = i + j)

    – Lucas Eder

    22 de septiembre de 2012 a las 8:31

Avatar de usuario de Peter Lawrey
pedro laurey

Un buen ejemplo de esta conversión es usar *= o /=

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

o

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

o

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

o

char ch="A";
ch *= 1.5;
System.out.println(ch); // prints 'a'

  • @AkshatAgarwal ch es un personaje. 65 * 1,5 = 97,5 -> ¿Entendido?

    – Sajal Dutta

    5 mayo 2014 a las 22:07

  • Sí, pero puedo ver a un principiante que viene aquí, lee esto y se va pensando que puede convertir cualquier carácter de mayúsculas a minúsculas multiplicándolo por 1.5.

    – Dawud ibn Karim

    28 de mayo de 2014 a las 9:25

  • @DavidWallace Cualquier personaje siempre que sea A 😉

    – Peter Lawrey

    28 mayo 2014 a las 12:56

  • @PeterLawrey y @DavidWallace revelaré su secretoch += 32 =D

    – Minhas Kamal

    16 de marzo de 2016 a las 5:29


Avatar de usuario de Thirler
Thirler

Muy buena pregunta. El Especificación del lenguaje Java confirma tu sugerencia.

Por ejemplo, el siguiente código es correcto:

short x = 3;
x += 4.6;

y da como resultado que x tenga el valor 7 porque es equivalente a:

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

  • O más divertido: “int x=33333333; x+=1.0f;”.

    – Super gato

    20/04/2017 a las 19:31

  • @supercat, ¿qué truco es este? Una conversión de ampliación que se redondea incorrectamente, seguida de una adición que en realidad no cambia el resultado, y vuelve a convertir a int para producir un resultado que es muy inesperado para las mentes humanas normales.

    – nexo

    21 de septiembre de 2018 a las 12:33

  • @neXus: en mi humilde opinión, las reglas de conversión deberían haber tratado double->float como ampliación, sobre la base de que los valores de tipo float identificar los números reales menos específicamente que los de tipo double. Si uno ve double como dirección postal completa y float como un código postal de 5 dígitos, es posible satisfacer una solicitud de un código postal con una dirección completa, pero no es posible especificar con precisión una solicitud de una dirección completa con solo un código postal. Convertir una dirección postal en un código postal es una operación con pérdidas, pero

    – Super gato

    21/09/2018 a las 15:05

  • …alguien que necesita una dirección completa generalmente no estaría pidiendo solo un código postal. Conversión de float->double es equivalente a convertir el código postal de EE. UU. 90210 con “US Post Office, Beverly Hills CA 90210”.

    – Super gato

    21 de septiembre de 2018 a las 15:07

Avatar de usuario de Umesh Awasthi
Umesh Awasti

Sí,

básicamente cuando escribimos

i += l; 

el compilador convierte esto en

i = (int)(i + l);

acabo de comprobar el .class código de archivo

Realmente es bueno saber

Avatar de usuario de dku.rajkumar
dku.rajkumar

tienes que lanzar desde long a int explicitly en caso de i = i + l luego compilará y dará la salida correcta. como

i = i + (int)l;

o

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

pero en caso de += simplemente funciona bien porque el operador hace implícitamente la conversión de tipos del tipo de variable derecha al tipo de variable izquierda, por lo que no es necesario convertirlos explícitamente.

  • En este caso, el “reparto implícito” podría tener pérdidas. En realidad, como dice @LukasEder en su respuesta, el elenco de int es interpretado después el +. El compilador lanzaría (¿debería?) una advertencia si realmente emitiera el long a int.

    – Romain

    3 de enero de 2012 a las 10:17


avatar de usuario de slevy1
slevy1

El problema aquí implica la conversión de tipos.

Cuando sumas int y long,

  1. El objeto int se convierte en largo y ambos se agregan y obtienes un objeto largo.
  2. pero el objeto largo no se puede convertir implícitamente a int. Entonces, tienes que hacerlo explícitamente.

Pero += está codificado de tal manera que hace una conversión de tipos. i=(int)(i+m)

  • En este caso, el “reparto implícito” podría tener pérdidas. En realidad, como dice @LukasEder en su respuesta, el elenco de int es interpretado después el +. El compilador lanzaría (¿debería?) una advertencia si realmente emitiera el long a int.

    – Romain

    3 de enero de 2012 a las 10:17


En Java, las conversiones de tipo se realizan automáticamente cuando el tipo de la expresión en el lado derecho de una operación de asignación se puede promover con seguridad al tipo de la variable en el lado izquierdo de la asignación. Así podemos asignar con seguridad:

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

Lo mismo no funcionará al revés. Por ejemplo, no podemos convertir automáticamente un largo a un int porque el primero requiere más almacenamiento que el segundo y, en consecuencia, se puede perder información. Para forzar tal conversión debemos realizar una conversión explícita.
Tipo – Conversión

  • oye, pero long es 2 veces más grande que float.

    – Nombre para mostrar

    30 de agosto de 2013 a las 10:17

  • A float no puede contener todo lo posible int valor, y un double no puede contener todo lo posible long valor.

    – Alex CDM

    09/09/2013 a las 20:41

  • ¿Qué quiere decir con “convertido de forma segura”? De la última parte de la respuesta, puedo deducir que se refería a la conversión automática (transmisión implícita), lo que, por supuesto, no es cierto en el caso de float -> long. flotante pi = 3.14f; largo b = pi; dará como resultado un error del compilador.

    – Lucas

    7 de noviembre de 2013 a las 13:21


  • Sería mejor diferenciar los tipos primitivos de coma flotante con los tipos primitivos enteros. No son lo mismo.

    – El águila pirotécnica

    22 de diciembre de 2015 a las 20:59

  • Java tiene reglas de conversión simplistas que requieren el uso de conversiones en muchos patrones donde el comportamiento sin conversiones coincidiría con las expectativas, pero no requiere conversiones en muchos patrones que generalmente son erróneos. Por ejemplo, un compilador aceptará double d=33333333+1.0f; sin quejarse, aunque el resultado 33333332.0 probablemente no sea lo que se pretendía (por cierto, la respuesta aritméticamente correcta de 33333334.0f se podría representar como float o int).

    – Super gato

    20/04/2017 a las 19:40

¿Ha sido útil esta solución?