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

Hasta hoy, pensaba que por ejemplo:

i += j;

Fue solo un atajo para:

i = i + j;

Pero si intentamos esto:

int i = 5;
long j = 8;

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

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

preguntado el 03 de enero de 12 a las 06:01

Me sorprende que Java lo permita, ya que es 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 5 de Ariane501, donde una conversión flotante de 64 bits a un entero de 16 bits provocó el bloqueo. -

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

Actualmente i+=(long)j; incluso se compilará bien. -

El impulso constante de un grupo 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 increíblemente precisa y otra que sea fácil de usar. Empujar Java desde ambas direcciones hace que sea inadecuado para ninguno de los grupos. -

si requiriera casting, ¿dónde lo pondrías? i += (int) f; lanza f antes de la adición, 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 un molde que significaría que desea emitir el valor después de agregar, pero antes de la asignación. -

11 Respuestas

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)), Donde T es el tipo de E1, excepto que E1 se evalúa solo una 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.

Respondido 09 Abr '20, 11:04

So i+=j compila como yo mismo comprobé, pero daría como resultado 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í? - malos_puntos_clave

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

Un buen ejemplo de este casting es usar * = o / =

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

or

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

or

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

or

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

Respondido el 03 de enero de 12 a las 10:01

@AkshatAgarwal ch es un char. 65 * 1.5 = 97.5 -> ¿Entendido? - Sajal Dutta

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

@DavidWallace Cualquier personaje siempre que sea A ;) - pedro laurey

@PeterLawrey & @DavidWallace Revelaré tu secreto- ch += 32 = D - Minhas Kamal

Muy buena pregunta. los 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);

Respondido 03 Abr '17, 20:04

O más divertido: "int x = 33333333; x + = 1.0f;". - Super gato

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

@neXus: En mi humilde opinión, las reglas de conversión deberían haber tratado double->float como ensanchamiento, sobre la base de que los valores de tipo float Identificar números reales de forma menos específica que los de tipo. double. Si uno ve double como una dirección postal completa y float como 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

... alguien que necesita una dirección completa no suele pedir solo un código postal. Conversión de float->double equivale a convertir el código postal de EE. UU. 90210 por "Oficina de correos de EE. UU., Beverly Hills CA 90210". - Super gato

Sí,

básicamente cuando escribimos

i += l; 

el compilador convierte esto a

i = (int)(i + l);

Acabo de comprobar el .class código de archivo.

Realmente es bueno saber

Respondido el 28 de enero de 15 a las 12:01

¿Puede decirme qué archivo de clase es este? - nanofaradio

@hexafracción: ¿a qué te refieres con archivo de clase? si preguntas sobre el archivo de clase que mencioné en mi publicación, entonces es la versión completa de tu clase de Java - Umesh Awasti

Oh, mencionaste "el" código de archivo de clase, lo que me llevó a creer que estaba involucrado un archivo de clase específico. Entiendo lo que quieres decir ahora. - nanofaradio

@Bogdan Eso no debería ser un problema con las fuentes utilizadas correctamente. Un programador que elige la fuente incorrecta para la programación debería pensar claramente en cómo proceder ... - glglgl

@glglgl No estoy de acuerdo en que uno deba confiar en la fuente para distinguir en esos casos ... pero todos tienen la libertad de elegir lo que creen que es mejor. - bogdan alexandru

necesitas emitir desde long a int explicitly en caso de i = i + l luego se compilará y dará la salida correcta. igual que

i = i + (int)l;

or

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 implícitamente realiza la conversión de tipos de tipo de variable derecha a tipo de variable izquierda, por lo que no es necesario convertir explícitamente.

Respondido el 03 de enero de 12 a las 10:01

En este caso, el "elenco implícito" podría tener pérdidas. En realidad, como @LukasEder afirma en su respuesta, el elenco de int es interpretado después de al +. El compilador lanzaría (¿debería?) Una advertencia si realmente lanzara el long a int. - romano

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

Cuando agrega 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 en int. Entonces, tienes que hacerlo explícitamente.

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

Respondido el 03 de diciembre de 14 a las 12:12

En Java, las conversiones de tipos 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 de manera segura al tipo de la variable en el lado izquierdo de la asignación. Por lo tanto, podemos asignar con seguridad:

 byte -> corto -> int -> largo -> flotante -> doble. 

Lo mismo no funcionará al revés. Por ejemplo, no podemos convertir automáticamente un long en 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

Respondido 27 ago 14, 06:08

Hey pero long es 2 veces más grande que float. - Nombre que se ve en la pagina

A float no puedo sostener todo lo posible int valor, y un double no puedo sostener todo lo posible long valor. - alex mdc

¿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 (conversión implícita), lo que, por supuesto, no es cierto en el caso de float -> long. flotador pi = 3.14f; largo b = pi; resultará en un error del compilador. - Lucas

Sería mejor diferenciar los tipos primitivos de punto flotante con tipos primitivos enteros. No son lo mismo. - ElPyroEagle

Java tiene reglas de conversión simplistas que requieren el uso de conversiones en muchos patrones donde el comportamiento sin conversiones de otro modo 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 quejas, aunque el resultado 33333332.0 probablemente no sea el esperado (por cierto, la respuesta aritméticamente correcta de 33333334.0f sería representable como float or int). - Super gato

A veces, esta pregunta se puede hacer en una entrevista.

Por ejemplo, cuando escribe:

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

no hay encasillamiento automático. En C ++ no habrá ningún error al compilar el código anterior, pero en Java obtendrás algo como Incompatible type exception.

Entonces, para evitarlo, debes escribir tu código así:

int a = 2;
long b = 3;
a += b;// No compilation error or any exception due to the auto typecasting

Respondido el 14 de enero de 15 a las 21:01

Gracias por la información sobre la comparación de op usar en C ++ a su uso en Java. Siempre me ha gustado ver estas trivialidades y creo que aportan algo a la conversación que a menudo puede quedar fuera. - Thomas

Sin embargo, la pregunta en sí is interesante, preguntando esto en una entrevista es estúpido. No prueba que la persona pueda producir un código de buena calidad, solo prueba que tuvo la paciencia suficiente para prepararse para un examen de certificado de Oracle. Y "evitar" los tipos incompatibles mediante el uso de una peligrosa conversión automática y así ocultar el posible error de desbordamiento, probablemente incluso Demuestra que la persona probablemente no pueda producir un código de buena calidad. ¡Malditos sean los autores de Java por todas estas auto-conversiones y auto-boxing y todo! - honza zidek

La principal diferencia es que con a = a + b, no hay encasillamiento, por lo que el compilador se enoja contigo por no encasillar. Pero con a += b, lo que realmente está haciendo es encasillar b a un tipo compatible con a. Así que si lo haces

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

Lo que realmente estás haciendo es:

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

Respondido el 06 de diciembre de 15 a las 14:12

Los operadores de asignación compuesta realizan una conversión restringida del resultado de la operación binaria, no del operando de la derecha. Entonces, en su ejemplo, 'a + = b' no es equivalente a 'a = a + (int) b' sino, como se explica en otras respuestas aquí, a 'a = (int) (a + b)'. - Lew Bloch

Sutil punto aquí ...

Hay un encasillamiento implícito para i+j cuando j es un doble y i es un int. Java SIEMPRE convierte un entero en un doble cuando hay una operación entre ellos.

Para aclarar i+=j donde i es un entero y j es un doble se puede describir como

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

Ver: esta descripción de casting implícito

Es posible que desee encasillar j a (int) en este caso para mayor claridad.

respondido 23 mar '18, 19:03

Creo que un caso más interesante podría ser int someInt = 16777217; float someFloat = 0.0f; someInt += someFloat;. Sumando cero a someInt no debería afectar su valor, pero promocionar someInt a float puede cambiar su valor. - Super gato

Especificación del lenguaje Java define E1 op= E2 ser equivalente a E1 = (T) ((E1) op (E2)) donde T es un tipo de E1 y E1 se evalúa una vez.

Esa es una respuesta técnica, pero es posible que se pregunte por qué es un caso. Bueno, consideremos el siguiente programa.

public class PlusEquals {
    public static void main(String[] args) {
        byte a = 1;
        byte b = 2;
        a = a + b;
        System.out.println(a);
    }
}

¿Qué imprime este programa?

¿Adivinaste 3? Lástima, este programa no se compilará. ¿Por qué? Bueno, resulta que la adición de bytes en Java está definido para devolver un int. Creo que esto se debió a que la máquina virtual de Java no define operaciones de bytes para guardar en códigos de bytes (después de todo, hay un número limitado de ellos), el uso de operaciones enteras en su lugar es un detalle de implementación expuesto en un lenguaje.

Pero si a = a + b no funciona, eso significaría a += b nunca funcionaría para bytes si E1 += E2 fue definido para ser E1 = E1 + E2. Como muestra el ejemplo anterior, ese sería el caso. Como un truco para hacer += El operador trabaja para bytes y cortos, hay una conversión implícita involucrada. No es un truco tan bueno, pero durante el trabajo de Java 1.0, la atención se centró en conseguir que se lanzara el lenguaje para empezar. Ahora, debido a la compatibilidad con versiones anteriores, este truco introducido en Java 1.0 no se pudo eliminar.

Respondido el 25 de junio de 19 a las 10:06

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.