Pregunta

acabo de código de sierra similar a esto:

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a == b);

        Integer c = 100, d = 100;
        System.out.println(c == d);
    }
}

Cuando se corrió, este bloque de código imprimirá:

false
true

entiendo por qué la primera es false: debido a que los dos objetos son objetos separados, por lo que el == compara las referencias. Pero no puedo averiguar, por qué es el segundo estado regresando true? ¿Hay alguna regla autoboxing extraña que se activa cuando el valor de un entero es en un cierto rango? ¿Qué está pasando aquí?

¿Fue útil?

Solución

La línea true es en realidad garantizada por la especificación del lenguaje. De href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7" 5.1.7 :

  

Si el valor p de ser en caja es cierto,   falso, un byte, un char en el rango   \ U0000 a \ u007f, o un int o corto   número entre -128 y 127, y luego dejar   R1 y R2 sean los resultados de cualquiera de dos   conversiones de boxeo de p. Es siempre   el caso de que r1 r2 ==.

La discusión continúa, lo que sugiere que, si bien se garantiza su segunda línea de salida, el primero es no (véase el último párrafo citado más abajo):

  

Lo ideal es que el boxeo un hecho primitivo   valor p, siempre daría una   referencia idénticos. En la práctica, esto   puede no ser factible usando existente   técnicas de implementación. Las normas   anteriormente son un compromiso pragmático. los   cláusula final anterior requiere que   ciertos valores comunes siempre encasillarán   en objetos indistinguibles. los   aplicación puede almacenar en caché estos, perezosamente   o con ansiedad.

     

Para otros valores, esta formulación   desautoriza ninguna hipótesis sobre la   la identidad de los valores en caja en el   parte del programador. Esto permitiría   (Pero no requiere) intercambio de algunos o   todas estas referencias.

     

Esto asegura que en el más común   casos, el comportamiento será el   uno deseada, sin imponer una indebida   penalización de rendimiento, especialmente en   pequeños dispositivos. Menos memoria limitada   implementaciones podría, por ejemplo,   almacenar en caché todos los caracteres y pantalones cortos, como   así como los números enteros y largos en el   gama de -32K -. + 32 K

Otros consejos

public class Scratch
{
   public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;  //1
        System.out.println(a == b);

        Integer c = 100, d = 100;  //2
        System.out.println(c == d);
   }
}

Salida:

false
true

Sí la primera salida es producida para la comparación de referencia; 'A' y 'b' - estos son dos de referencia diferente. En el punto 1, en realidad dos referencias se crean que es similar como -

Integer a = new Integer(1000);
Integer b = new Integer(1000);

La segunda salida se produce porque el JVM trata de salvar la memoria, cuando el Integer cae en un rango (de -128 a 127). En el punto 2 se crea ninguna nueva referencia de tipo entero de 'd'. En lugar de crear un nuevo objeto para la variable de referencia de tipo Integer 'd', sólo se asigna con objeto creado previamente referenciado por 'c'. Todos estos son realizados por JVM.

Estas normas de ahorro de memoria no son sólo para los enteros. para la memoria fin de salvación, dos instancias de los siguientes objetos envolventes (mientras se crea a través del boxeo), siempre serán == donde sus valores primitivos son los mismos -

  • Boolean
  • Byte
  • Carácter de \ u0000 a \u007f (7f es 127 en decimal)
  • Short y número entero de -128 a 127

objetos de enteros en un rango (creo que tal vez -128 a 127) obtener en caché y volver a utilizar. Enteros fuera de ese rango obtienen un nuevo objeto cada vez.

Sí, hay una regla autoboxing extraño que entra en acción cuando los valores están en un cierto rango. Cuando se asigna una constante a una variable de objeto, nada en la definición del lenguaje dice un nuevo objeto debe se creará. Se puede reutilizar un objeto existente de la memoria caché.

De hecho, la JVM normalmente almacenar una memoria caché de enteros pequeños para este fin, así como valores como Boolean.TRUE y Boolean.FALSE.

Esto es un punto interesante. En el libro Effective Java sugiere siempre para anular es igual para sus propias clases. Además de eso, para comprobar la igualdad de las dos instancias de objetos de una clase Java utilice siempre el método es igual.

public class Scratch
{
    public static void main(String[] args)
    {
        Integer a = 1000, b = 1000;
        System.out.println(a.equals(b));

        Integer c = 100, d = 100;
        System.out.println(c.equals(d));
    }
}

retornos:

true
true

Mi conjetura es que Java mantiene una caché de pequeños números enteros que ya están 'enmarcados', ya que son muy comunes y se ahorra una diablos de un montón de tiempo para la reutilización de un objeto existente que crear una nueva.

En Java las obras de boxeo en el rango entre -128 y 127 para un entero. Cuando está utilizando los números en este rango se puede comparar con el operador ==. Para Entero objetos fuera del rango que tiene que usar es igual.

asignación directa de un int literal a una referencia entero es un ejemplo de auto-boxing, donde el valor literal de código de conversión objeto es manejado por el compilador.

Así que durante convertidos compilador fase de compilación Integer a = 1000, b = 1000; a Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.

Por lo tanto, es el método Integer.valueOf() que en realidad nos da los objetos enteros, y si nos fijamos en el código fuente del método Integer.valueOf() podemos ver claramente los objetos cachés método enteros encuentra entre -128 y 127 (ambos inclusive).

/**
 *
 * This method will always cache values in the range -128 to 127,
 * inclusive, and may cache other values outside of this range.
 *
 * @param  i an {@code int} value.
 * @return an {@code Integer} instance representing {@code i}.
 * @since  1.5
 */
 public static Integer valueOf(int i) {
     if (i >= IntegerCache.low && i <= IntegerCache.high)
         return IntegerCache.cache[i + (-IntegerCache.low)];
     return new Integer(i);
 }

Así que en lugar de crear y devolver nuevos objetos de enteros, Integer.valueOf() el método devuelve objetos de enteros de la IntegerCache interna si el int literal pasado es mayor que -128 y menos de 127.

Java almacena en caché estos objetos enteros porque este rango de números enteros se utiliza mucho en el día a día de programación que ahorra algo de memoria indirecta.

La memoria caché se inicia en el primer uso cuando la clase se carga en memoria debido al bloque estático. El rango máximo de la memoria caché puede ser controlado por la opción -XX:AutoBoxCacheMax JVM.

Este comportamiento de almacenamiento en caché no es aplicable a los objetos de enteros solamente, similar a Integer.IntegerCache también tenemos ByteCache, ShortCache, LongCache, CharacterCache para Byte, Short, Long, Character respectivamente.

Se puede leer más en mi artículo Integer de Java Cache - ¿Por Integer.valueOf (127) == Integer.valueOf (127) es cierto .

En Java 5, una nueva característica se introdujo para guardar la memoria y mejorar el rendimiento de tipo entero objetos manipulados. objetos de enteros se almacenan en caché y volver a utilizar internamente a través de los mismos objetos referenciados.

  1. Esto es aplicable para valores enteros en el rango de entre -127-127 (Valor Max entero).

  2. Este almacenamiento en caché de enteros sólo funciona en autoboxing. Entero objetos voluntad No almacenar en caché cuando se construyen utilizando el constructor.

Para más detalles pls pasan por acoplamiento abajo:

Entero Cache en detalle

Si comprobamos el código fuente de obeject Integer, vamos a encontrar la fuente del método valueOf como este:

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

lo que puede explicar por qué los objetos Integer, que en el intervalo de -128 (Integer.low) a 127 (Integer.high), son los mismos objetos referenciados durante el autoboxing. Y podemos ver que hay una IntegerCache clase se encarga de la matriz de caché Integer, que es una clase interna estática privada de clase Integer.

Hay otro ejemplo interesante puede ayudar a entender esta situación extraña:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {

      Class cache = Integer.class.getDeclaredClasses()[0]; 
      Field myCache = cache.getDeclaredField("cache"); 
      myCache.setAccessible(true);

      Integer[] newCache = (Integer[]) myCache.get(cache); 
      newCache[132] = newCache[133]; 

      Integer a = 2;
      Integer b = a + a;
      System.out.printf("%d + %d = %d", a, a, b); //The output is: 2 + 2 = 5    

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top