¿Por qué los operadores de asignación compuesta + =, - =, * =, / = de Java no requieren conversión?
Frecuentes
Visto 307,853 equipos
3765
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)
?
11 Respuestas
2530
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 aE1 = (T)((E1) op (E2))
, DondeT
es el tipo deE1
, excepto queE1
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
501
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
265
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
183
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
93
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
64
El problema aquí implica la fundición de tipos.
Cuando agrega int y long,
- El objeto int se convierte en largo y ambos se agregan y obtienes un objeto largo.
- 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
55
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
46
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
25
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
12
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
7
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 java casting operators variable-assignment assignment-operator or haz tu propia pregunta.
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. - SQLDiver
En un sistema de control de vuelo escrito en Java, esta sería la menor de tus preocupaciones @SQLDiver - Ross Drew
Actualmente
i+=(long)j;
incluso se compilará bien. - Tharindu SathischandraEl 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. - Bill K
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. - Norill Tempest