Domanda

Ho appena codice sega simile a questo:

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);
    }
}

Quando Ran, questo blocco di codice stamperà:

false
true

capisco perché il primo è false: perché i due oggetti sono oggetti separati, in modo che il == confronta i riferimenti. Ma io non riesco a capire, perché è la seconda istruzione tornando true? C'è una strana regola autoboxing che calci a quando il valore di un intero è in un certo intervallo? Che cosa sta succedendo qui?

È stato utile?

Soluzione

La linea true è effettivamente garantita dalla specifica del linguaggio. Da href="http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.7" 5.1.7 :

  

Se il valore p essere inscatolato è vero,   falso, un byte, un char nella gamma   \ U0000 a \ u007F, o un int o corto   numero compreso tra -128 e 127, poi lasciare   r1 e r2 essere i risultati di due qualsiasi   conversioni boxe di p. E 'sempre   il caso che r1 == r2.

La discussione va avanti, il che suggerisce che anche se la seconda linea di uscita è garantita, la prima non è (vedi l'ultimo paragrafo citato qui di seguito):

  

Idealmente, la boxe un dato primitivo   valore p, sarebbe sempre produrre un   riferimento identici. In pratica, questo   potrebbe non essere possibile utilizzando esistenti   tecniche di implementazione. Le regole   sopra sono un compromesso pragmatico. Il   clausola finale precedente richiede che   certi valori comuni sempre essere inscatolati   in oggetti indistinguibili. Il   implementazione può memorizzare nella cache questi, pigramente   o entusiasmo.

     

Per altri valori, questa formulazione   disabilita qualsiasi ipotesi circa il   l'identità dei valori in scatola sul   parte del programmatore. Ciò consentirebbe   (Ma non richiede) la condivisione di alcuni o di   tutti questi riferimenti.

     

In questo modo, nella maggior parte dei comuni   casi, il comportamento sarà il   desiderato uno, senza imporre un indebito   penalizzazione delle prestazioni, in particolare su   piccoli dispositivi. Meno memoria limitata   implementazioni potrebbe, per esempio,   memorizzare nella cache tutti i personaggi e cortometraggi, come   così come numeri interi e long nel   gamma di -32K -. + 32K

Altri suggerimenti

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);
   }
}

Output:

false
true

Sì la prima uscita è prodotta per confrontare riferimento; 'A' e 'b' - questi sono due diversi di riferimento. Al punto 1, in realtà due riferimenti sono creati, che è simile a -

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

La seconda uscita è prodotta perché l'JVM tenta di risparmiare memoria, quando il Integer cade in un intervallo (da -128 a 127). Al punto 2 non viene creato nessun nuovo riferimento di tipo Integer per 'd'. Invece di creare un nuovo oggetto per la variabile di riferimento tipo integer 'd', è assegnato soltanto con oggetto creato in precedenza fa riferimento 'c'. Tutti questi sono fatto da JVM.

Queste regole risparmio di memoria non sono solo per intero. a scopo di risparmio di memoria, due istanze dei seguenti oggetti wrapper (mentre creato attraverso la boxe), sarà sempre == dove i loro valori primitivi sono gli stessi -

  • booleana
  • Byte
  • Carattere da \ u0000 per \u007f (7f è 127 in decimale)
  • Breve e Integer da -128 a 127

Integer oggetti in un certo range (penso che forse -128 a 127) vanno nella cache e riutilizzato. Interi al di fuori di tale intervallo ottenere un nuovo oggetto ogni volta.

Sì, c'è una regola autoboxing strano che calci a quando i valori sono in un certo intervallo. Quando si assegna una costante ad una variabile oggetto, niente nella definizione del linguaggio, dice un nuovo oggetto deve essere creato. Si può riutilizzare un oggetto esistente dalla cache.

In realtà, la JVM solito memorizzare una cache di piccoli numeri interi per questo scopo, come pure valori come Boolean.TRUE e Boolean.FALSE.

Questo è un punto interessante. Nel libro Effective Java suggerisce sempre di sostituzione è uguale per le proprie classi. Inoltre che, per controllare l'uguaglianza per due istanze di oggetti di una classe Java utilizzare sempre il metodo equals.

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));
    }
}

restituisce:

true
true

La mia ipotesi è che Java mantiene una cache di piccoli numeri interi che sono gia 'in scatola', perché sono così molto comuni e si risparmia un diavolo di un sacco di tempo per il riutilizzo di un oggetto esistente piuttosto che crearne uno nuovo.

In Java i lavori boxe nell'intervallo compreso tra -128 e 127 per i numeri interi. Quando si utilizza i numeri in questo intervallo si può confrontare con l'operatore ==. Per Integer oggetti di fuori del campo si deve utilizzare è uguale.

l'assegnazione diretta di un int letterale ad un riferimento Integer è un esempio di auto-boxing, dove il valore letterale di codice di conversione oggetto viene gestito dal compilatore.

Quindi, durante fase di compilazione del compilatore converte Integer a = 1000, b = 1000; a Integer a = Integer.valueOf(1000), b = Integer.valueOf(1000);.

Quindi è il metodo Integer.valueOf() che in realtà ci dà gli oggetti interi, e se guardiamo il codice sorgente del metodo Integer.valueOf() possiamo vedere chiaramente le cache metodo interi oggetti nella gamma da -128 a 127 (compreso).

/**
 *
 * 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);
 }

Così, invece di creare e restituire nuovi oggetti interi, Integer.valueOf() il metodo restituisce interi oggetti dal IntegerCache interno qualora l'int letterale passato è maggiore di -128 e inferiore a 127.

Java memorizza nella cache questi oggetti interi, perché questa serie di numeri interi si abitua molto in giorno per giorno di programmazione che consente di risparmiare indirettamente po 'di memoria.

La cache viene inizializzata al primo utilizzo quando la classe viene caricato in memoria a causa del blocco statico. La portata massima della cache può essere controllato dall'opzione -XX:AutoBoxCacheMax JVM.

Questo comportamento della cache non è applicabile per oggetti solo numero intero, simile a Integer.IntegerCache abbiamo anche ByteCache, ShortCache, LongCache, CharacterCache per Byte, Short, Long, Character rispettivamente.

Si può leggere di più sul mio articolo Java Integer Cache - Perché Integer.valueOf (127) == Integer.valueOf (127) È vero .

In Java 5, una nuova funzionalità è stata introdotta per salvare la memoria e migliorare le prestazioni per gli oggetti di tipo Integer manipolazioni. oggetti interi sono memorizzati nella cache internamente e riutilizzati attraverso gli stessi oggetti di riferimento.

  1. Questo è valido per i valori interi nella gamma tra -127 e +127 (Valore massimo intero).

  2. Questa caching Integer funziona solo su autoboxing. Integer Objects Non essere memorizzate nella cache quando vengono costruiti utilizzando il costruttore.

Per maggiori dettagli pls passano sotto il collegamento:

Integer cache in dettaglio

Se controlliamo il codice sorgente di Integer obeject, troveremo la fonte del metodo di valueOf proprio come questo:

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

che può spiegare perché Integer oggetti, che nell'intervallo da -128 (Integer.low) a 127 (Integer.high), sono gli stessi oggetti di riferimento durante l'autoboxing. E possiamo vedere c'è una IntegerCache di classe si prende cura della matrice di cache Integer, che è una classe interna statica privata di classe Integer.

C'è un altro esempio interessante può aiutarci a capire questa situazione strana:

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    

}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top