¿Por qué int i = 1024 * 1024 * 1024 * 1024 compilar sin errores?


El límite de int es de -2147483648 a 2147483647.

Si entro

int i = 2147483648;

Entonces Eclipse pedirá un subrayado rojo bajo "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 sea una pregunta básica en Java, pero no tengo idea de por qué la segunda variante no produce ningún error.

 150
Author: devnull, 2014-07-10

5 answers

No hay nada malo con esa declaración; solo estás multiplicando 4 números y asignándolo a un int, simplemente sucede que hay un desbordamiento. Esto es diferente a asignar un único literal , que sería comprobado en tiempo de compilación.

Es el fuera de límites literal 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 es todavía calculado en tiempo de compilación porque 1024 * 1024 * 1024 * 1024 es un expresión constante:

int i = 1024 * 1024 * 1024 * 1024;

Se convierte en:

   0: iconst_0      
   1: istore_1      

Observe 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):

Es un error en tiempo de compilación si un literal decimal de tipo int es mayor que 2147483648 (231), o si el literal decimal 2147483648 aparece en cualquier lugar que no sea como el operando del operador unario menos(§15.15.4).

 230
Author: arshajii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-14 23:30:44

1024 * 1024 * 1024 * 1024 y 2147483648 no tienen el mismo valor en Java.

En realidad, 2147483648 NI SIQUIERA ES UN VALOR(aunque 2147483648L lo es) en Java. El compilador literalmente no sabe qué es, o cómo usarlo. Así que se queja.

1024 es un int válido en Java, y un int válido multiplicado por otro int válido, es siempre un int válido. Incluso si no es el mismo valor que esperarías intuitivamente porque el cálculo se desbordará.

Ejemplo

Considere el siguiente ejemplo de código:

public static void main(String[] args) {
    int a = 1024;
    int b = a * a * a * a;
}

¿Esperarías que esto generara un error de compilación? Se vuelve un poco más resbaladizo ahora.
¿Qué pasa si ponemos un bucle con 3 iteraciones y multiplicamos en el bucle?

El compilador puede optimizar, pero no puede cambiar el comportamiento del programa mientras lo hace.


Algo de información sobre cómo se maneja este caso:

En Java y muchos otros lenguajes, los enteros consistirán en un fijo número de bits. Los cálculos que no encajan en el número dado de bits se desbordarán ; el cálculo se realiza básicamente módulo 2^32 en Java, después de lo cual el valor se convierte de nuevo en un con signo entero.

Otros lenguajes o API usan un número dinámico de bits (BigInteger en Java), levantan una excepción o establecen el valor a un valor mágico como not-a-number.

 43
Author: Cruncher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-16 18:13:47

No tengo idea de por qué la segunda variante no produce ningún error.

El comportamiento que sugiere {es decir, la producción de 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 is es una característica . Para que pueda usar cualquier característica, la característica debe ser pensada, 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 sucedió, y por lo tanto no tiene la función. No se cual; tendrías que preguntarle a un diseñador Java.

Para C#, todas esas cosas sucedieron fourteen hace unos catorce años now y así el programa correspondiente en C# ha producido un error desde C# 1.0.

 15
Author: Eric Lippert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-14 18:54:09

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 intentes

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 fuera de rango.

Así que las operaciones con int-valores (y eso incluye las 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.

 12
Author: piet.t,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-12 22:45:52

R:, Porque no es un error.

Fondo: 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 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, resta UINT_MAX + 1 siempre que el resultado sea 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 suma o resta 2^32 hasta que el resultado está en el rango permitido. Así que la declaración es completamente legal y no en error. Simplemente no produce el resultado que puede haber esperado.

Seguramente puede argumentar si este comportamiento es útil, y si el compilador debe darle una advertencia. Yo diría personalmente que una advertencia sería muy útil, pero un error sería incorrecto ya que es Java legal.

 4
Author: gnasher729,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-16 09:06:08