El límite de int
es de -2147483648 a 2147483647.
Si ingreso
int i = 2147483648;
entonces Eclipse mostrará un subrayado rojo debajo de "2147483648".
Pero si hago esto:
int i = 1024 * 1024 * 1024 * 1024;
Se 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.
2147483648
: este literal no tiene sentido.Respuestas:
No hay nada malo con esa declaración; solo estás multiplicando 4 números y asignándolos a un int, simplemente sucede que hay un desbordamiento. Esto es diferente de asignar un solo literal , que se verificaría en los límites en tiempo de compilación.
Es el literal fuera de límites lo que causa el error, no la asignación :
Por el contrario, un
long
literal compilaría bien:Tenga en cuenta que, de hecho, el resultado es todavía calcula en tiempo de compilación, porque
1024 * 1024 * 1024 * 1024
es una expresión constante :se convierte en:
Tenga en cuenta que el resultado (
0
) simplemente se carga y almacena, y no se produce ninguna multiplicación.De JLS §3.10.1 (gracias a @ChrisK por mencionarlo en los comentarios):
fuente
-1 + 1
, es inofensivo; pero1024^4
podría sorprender a las personas con resultados totalmente inesperados, lejos de lo que esperarían ver. Creo que debería haber al menos una advertencia o nota para el usuario, y no ignorarlo en silencio.1024 * 1024 * 1024 * 1024
y2147483648
no tienen el mismo valor en Java.En realidad,
2147483648
NO ES UN VALOR (aunque lo2147483648L
sea) en Java. El compilador literalmente no sabe qué es ni cómo usarlo. Entonces se queja.1024
es un int válido en Java, y un válidoint
multiplicado por otro válidoint
, siempre es válidoint
. Incluso si no es el mismo valor que esperaría intuitivamente porque el cálculo se desbordará.Ejemplo
Considere el siguiente ejemplo de código:
¿Esperaría que esto generara un error de compilación? Ahora se vuelve un poco más resbaladizo.
¿Qué pasa si ponemos un ciclo con 3 iteraciones y multiplicado en el ciclo?
El compilador puede optimizar, pero no puede cambiar el comportamiento del programa mientras lo hace.
Alguna información sobre cómo se maneja realmente este caso:
En Java y muchos otros lenguajes, los enteros consistirán en un número fijo de bits. Los cálculos que no caben en el número de bits dado se desbordarán ; el cálculo se realiza básicamente módulo 2 ^ 32 en Java, después de lo cual el valor es de nuevo convertida en un firmado entero.
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 no un número.fuente
2147483648
NO ES AUN UN VALOR (aunque lo2147483648L
sea)", realmente consolidó el punto que @arshajii estaba tratando de hacer.1024 * 1024 * 1024 * 1024
se maneje, realmente quería enfatizar que no es lo mismo que escribir2147473648
. Hay muchas formas (y usted ha enumerado algunas) de que un idioma podría tratarlo. Está razonablemente separado y es útil. Entonces lo dejo. Mucha información se hace cada vez más necesaria cuando tienes una respuesta de alto rango en una pregunta popular.El comportamiento que sugiere, es decir, la producción de un mensaje 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 entero , es una característica . Para que pueda utilizar cualquier función, debe pensar en ella, considerarla una buena idea, diseñar, especificar, implementar, probar, documentar y enviar a los usuarios.
Para Java, una o más de las cosas en esa lista no sucedieron y, por lo tanto, no tiene la función. No se cual; tendrías que preguntarle a un diseñador de Java.
Para C #, todas esas cosas sucedieron, hace unos catorce años, por lo que el programa correspondiente en C # ha producido un error desde C # 1.0.
fuente
Además de la respuesta de arshajii, quiero mostrar una cosa más:
No es la asignación la que causa el error, sino simplemente el uso del literal . Cuando intentas
notarás que también causa un error de compilación ya que el lado derecho todavía es un
int
literal y está fuera de rango.Por lo tanto, las operaciones con
int
valores (y eso incluye asignaciones) pueden desbordarse sin un error de compilación (y sin un error de tiempo de ejecución también), pero el compilador simplemente no puede manejar esos literales demasiado grandes.fuente
A: Porque no es un error.
Antecedentes: la multiplicación
1024 * 1024 * 1024 * 1024
conducirá a un desbordamiento. Un desbordamiento es muy a menudo un error. Diferentes lenguajes de programación producen un comportamiento diferente cuando se producen 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, agregueUINT_MAX + 1
siempre que el resultado sea negativo, resteUINT_MAX + 1
siempre que el resultado sea mayor queUINT_MAX
).En el caso de Java, si el resultado de una operación con
int
valores no está en el rango permitido, conceptualmente Java suma o resta 2 ^ 32 hasta que el resultado esté en el rango permitido. Entonces, la declaración es completamente legal y no está equivocada. Simplemente no produce el resultado que esperaba.Seguramente puede discutir si este comportamiento es útil y si el compilador debería darle una advertencia. Yo personalmente diría que una advertencia sería muy útil, pero un error sería incorrecto ya que es Java legal.
fuente