java - una - ¿Por qué int i=1024*1024*1024*1024 compila sin error?
jstl ejemplos (5)
No tengo idea de por qué la segunda variante no produce ningún error.
El comportamiento que sugiere, es decir, la producción de mensajes de diagnóstico cuando un cálculo produce un valor que es mayor que el valor más grande que se puede almacenar en un número entero , es una característica . Para que pueda usar cualquier función, la función debe ser considerada, considerada como una buena idea, diseñada, especificada, implementada, probada, documentada y enviada a los usuarios.
Para Java, una o más de las cosas en esa lista no ocurrieron, y por lo tanto no tiene la característica. No sé cuál; tendrías que preguntarle a un diseñador de Java.
Para C #, todas esas cosas sucedieron hace catorce años, y el programa correspondiente en C # produjo un error desde C # 1.0.
El límite de int
es de -2147483648 a 2147483647.
Si ingreso
int i = 2147483648;
luego Eclipse mostrará un subrayado rojo debajo de "2147483648".
Pero si hago esto:
int i = 1024 * 1024 * 1024 * 1024;
compilará bien
public class Test {
public static void main(String[] args) {
int i = 2147483648; // error
int j = 1024 * 1024 * 1024 * 1024; // no error
}
}
Tal vez es una pregunta básica en Java, pero no tengo idea de por qué la segunda variante no produce ningún error.
Además de la respuesta de arshajii, quiero mostrar una cosa más:
No es la asignación lo que causa el error, sino simplemente el uso del literal . Cuando intentas
long i = 2147483648;
notarás que también causa un error de compilación ya que el lado derecho sigue siendo un int
-literal y está fuera de rango.
Así que las operaciones con valores- int
(y eso incluye asignaciones) pueden desbordarse sin un error de compilación (y sin un error de tiempo de ejecución), pero el compilador simplemente no puede manejar esos literales demasiado grandes.
No hay nada malo con esa declaración; solo estás multiplicando 4 números y asignándoselos a un int; simplemente sucede que hay un desbordamiento. Esto es diferente a la asignación de un solo literal , que se verificará en los límites en tiempo de compilación.
Es el literal fuera de límites que causa el error, no la asignación :
System.out.println(2147483648); // error
System.out.println(2147483647 + 1); // no error
Por el contrario, un long
literal compilaría bien:
System.out.println(2147483648L); // no error
Tenga en cuenta que, de hecho, el resultado todavía se calcula en tiempo de compilación porque 1024 * 1024 * 1024 * 1024
es una expresión constante :
int i = 1024 * 1024 * 1024 * 1024;
se convierte en:
0: iconst_0
1: istore_1
Tenga en cuenta que el resultado ( 0
) simplemente se carga y almacena, y no tiene lugar ninguna multiplicación.
De JLS §3.10.1 (gracias a @ChrisK por mencionarlo en los comentarios):
Es un error en tiempo de compilación si un literal decimal de tipo
int
es mayor que2147483648
(2 31 ), o si el literal decimal2147483648
aparece en cualquier lugar que no sea el operando del operador unario negativo ( §15.15.4 ).
1024 * 1024 * 1024 * 1024
y 2147483648
no tienen el mismo valor en Java.
En realidad, 2147483648
NO ES AUN EL VALOR (aunque 2147483648L
) en Java. El compilador literalmente no sabe qué es ni cómo usarlo. Entonces gime.
1024
es una int válida en Java, y una int
válida multiplicada por otra int
válida, siempre es una int
válida. Incluso si no es el mismo valor que esperaría intuitivamente porque el cálculo se desbordará.
Ejemplo
Considere la siguiente muestra de código:
public static void main(String[] args) {
int a = 1024;
int b = a * a * a * a;
}
¿Esperaría que esto genere un error de compilación? Se vuelve un poco más resbaladizo ahora.
¿Qué pasa si colocamos un ciclo con 3 iteraciones y multiplicamos en el ciclo?
El compilador puede optimizar, pero no puede cambiar el comportamiento del programa mientras lo hace.
Información sobre cómo se maneja este caso:
En Java y en muchos otros lenguajes, los enteros consistirán en un número fijo de bits. Los cálculos que no encajan en la cantidad dada de bits se overflow ; el cálculo se realiza básicamente con el módulo 2 ^ 32 en Java, después de lo cual el valor se vuelve a convertir en un entero con signo.
Otros lenguajes o API utilizan un número dinámico de bits ( BigInteger
en Java), generan una excepción o establecen el valor en un valor mágico como not-a-number.
R: Porque no es un error.
Antecedentes: la multiplicación 1024 * 1024 * 1024 * 1024
dará lugar a un desbordamiento. Un desbordamiento es muy a menudo un error. Los diferentes lenguajes de programación producen un comportamiento diferente cuando ocurren desbordamientos. Por ejemplo, C y C ++ lo llaman "comportamiento indefinido" para enteros con signo, y el comportamiento se define como enteros sin signo (tome el resultado matemático, agregue UINT_MAX + 1
, siempre que el resultado sea negativo, reste UINT_MAX + 1
siempre que el resultado es mayor que UINT_MAX
).
En el caso de Java, si el resultado de una operación con valores int
no está en el rango permitido, conceptualmente Java agrega o resta 2 ^ 32 hasta que el resultado se encuentre en el rango permitido. Entonces la declaración es completamente legal y no es un error. Simplemente no produce el resultado que esperabas.
Seguramente puede argumentar si este comportamiento es útil y si el compilador debería darle una advertencia. Diría personalmente que una advertencia sería muy útil, pero un error sería incorrecto ya que es legal Java.