2009-07-18 12 views
8

Considerate questo codice:comportamento incoerente sul == di java

class test { 
    public static void main(String[] args) { 
     test inst_test = new test(); 
     int i1 = 2000; 
     int i2 = 2000; 
     int i3 = 2; 
     int i4 = 2; 
     Integer Ithree = new Integer(2); // 1 
     Integer Ifour = new Integer(2); // 2 
     System.out.println(Ithree == Ifour); 
     inst_test.method(i3 , i4); 
     inst_test.method(i1 , i2); 
    } 
    public void method(Integer i , Integer eye) { 
     System.out.println(i == eye); 
    } 
} 

Esso stampa:

false 
true 
false 

Capisco la prima false, l'operatore == solo controlli se due riferimenti stanno lavorando sullo stesso oggetto, che in questo caso non lo sono.

I seguenti numeri true e false mi graffiano la testa. Perché Java considera i3 e i4 uguali ma i1 e i2 diversi? Entrambi sono stati incapsulati su Integer, non valutare su false? C'è una ragione pratica per questa incoerenza?

+2

Credo che FindBugs ti direbbe del tuo errore. –

risposta

15

Autoboxing di primitive in oggetti (come quello usato nelle vostre chiamate a method utilizza una cache di piccoli valori Dal Java Language Specification section 5.1.7:.

Se il valore p essere inscatolato è vero, falso, un byte, un char nell'intervallo \ 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 p. è sempre il caso che r1 == r2

Anche la parte di discussione delle specifiche immediatamente successive è interessante. In particolare una JVM può memorizzare nella cache più valori se vuole - non si può essere sicuri dei risultati di fare:

Integer i1 = 129; 
Integer i2 = 129; 
boolean b = (i1 == i2); 
+0

Questa è una logica seriamente cattiva - immagino sia fatta per motivi di prestazioni? –

+0

Questo ha davvero un vantaggio? Penso che sia una decisione di design offuscante. – andandandand

+0

6u14 (e varie varianti precedenti p) ha un'opzione per aumentare l'intervallo internato. È importante per determinati benchmark e stili di programmazione. –

2

Ciò è dovuto al fatto che il boxing rende gli interi al di sotto di un determinato valore (128, penso) fare riferimento a un oggetto precostruito e valori superiori a nuovi oggetti.

7

Quando autoboxing, i numeri interi da -128 a 127 vengono memorizzati nella cache e viene restituito lo stesso oggetto wrapper. Lo stesso con valori booleani e valori di char tra \ u0000 e \ u007F

Questo è ciò che si ottiene la maggior parte del tempo, tuttavia dipende dall'implementazione di JVM.

+3

Pensavo che dipendesse anche da JVM, ma in realtà è nelle specifiche. –

+2

(O meglio, è specificato per quei valori, ma non per gli altri.) –

0

Direi che il wrapping tenta di minimizzare il numero di oggetti Integer e crea solo un oggetto che rappresenta 2 anche di memoria.

Ricorda solo di non usare mai == sugli oggetti non sai mai cosa succede.

+0

sì, come molti hanno detto, non usare == a meno che non si ricercino effetti specifici supportati da "sa cosa succede" e in generale: booleano booleano = Booleano.valueOf (i.intValue() == eye.intValue()); System.out.println (booLean.toString()); –

0

classe Integer contiene una cache di alcuni casi di uso frequente. La gamma di valori varia generalmente da JVM a JVM (a volte è anche configurabile), ma in generale il codice in questione è qualcosa di simile:

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

(codice da sole JDK 1.6)

questo è come stringa di internato, dal momento che entrambi salva la memoria e consente l'uguaglianza di test usando un riferimento (es== in luogo di uguale)

1

Autoboxing utilizza Integer.valueOf (i), non new Integer (i), per costruire un oggetto della classe Integer.

Come gli altri hanno detto, valueOf() utilizza una cache, principalmente per l'efficienza dello spazio.

Non utilizzare == sui tipi di riferimento, è quasi sempre un errore.

0

Autoboxing utilizza un meccanismo di memorizzazione nella cache. Di solito non devi mai fare affidamento su ==, usa sempre equals per controllare l'uguaglianza.

Problemi correlati