¿Por qué la asignación compuesta en Java no detecta problemas de desbordamiento?
-
14-11-2019 - |
Pregunta
Para mi sorpresa, resulta que el siguiente código se compilará sin siquiera advertencias:
public void test()
{
int value = 2000000000;
long increment = 1000000000;
value += increment;
}
Mientras que esto genera un error en tiempo de compilación, como era de esperar:
public void test()
{
int value = 2000000000;
long increment = 1000000000;
value = value + increment;
}
Lo revisé y, de hecho, el JLS (sección 15.26.2) dice lo siguiente:
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.
Esto me parece ridículo.¿Por qué sintieron la necesidad de elegir explícitamente aquí?Parece que la conversión automática de tipos habría manejado la ampliación de todos modos, y es casi seguro que un estrechamiento automático de esta manera dará como resultado un desbordamiento de enteros.
Solución
aquí es unoExplicación:
Cuando realiza una asignación (el fragmento de código de primer código), Java hace cumplir el tipo de tipo porque el LHS y RHS pueden ser muy independientes entre sí.
Pero el operador compuesto es más como un operador incremental.El += Modifica el valor de la variable. involucrado, en lugar de asignar un nuevo Valor a la variable.Cuando modificas un byte, espera un byte como el resultado.Para hacer la vida más fácil, Java hace una conversión de tipo implícito para operadores compuestos porque son modificadores.
Otros consejos
Los operadores de asignación compuesta están especificados por JLS (15.26.2) como sigue:
"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 sólo una vez."
En este caso E1 es del tipo int
E2 es de tipo long
, y op es +
.Entonces esto es equivalente a:
value = (int)(value + increment);
La adición de un int
y un long
da un long
que luego se devuelve a un int
antes de la asignación.Todo eso está bien, por lo tanto, no hay errores de compilación.
La diferencia entre esto y la asignación simple (es decir, value = value + increment;
), es que la tarea simple no tiene encasillamiento.
OK entonces por qué ¿Lo definieron así?
Creo que la razón es hacer que ejemplos como este funcionen:
byte b = ...
b += 1;
Sin el encasillamiento, b += 1
Sería un error de compilación y necesitarías escribirlo como:
b += (byte) 1;
Este enlace ha analizado el problema que ha superado.
Comportamiento variable para la posible pérdida de precisión
para evitar sorpresas desagradables, no Utilice operadores de asignación compuesta en Variables de tipo byte, corto, o carbonizarse.Al usar la asignación compuesta Operadores en las variables de tipo int, Asegúrate de que la expresión en el lado derecho no es de tipo largo, flotando, o doble.Al usar el compuesto Operadores de asignación en variables de Tipo flotante, asegúrese de que la expresión en el lado derecho no es de tipo doble.Estas reglas son suficientes para evitar que el compilador genere Pelos de estrechamiento peligroso.