Comportamento incoerente su == di java

Considera questo codice:

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

Stampa:

 false true false 

Capisco il primo false , l’operatore == controlla solo se due riferimenti stanno lavorando sullo stesso object, che in questo caso non lo sono.

Le seguenti true e false mi fanno grattarmi la testa. Perché Java considera i3 e i4 uguali ma i1 e i2 diversi? Entrambi sono stati spostati su Integer, non dovrebbero entrambi essere valutati come falsi? C’è una ragione pratica per questa incoerenza?

Autoboxing di primitive negli oggetti (come utilizzato nelle chiamate al method utilizza una cache di valori piccoli.) Dalla sezione 5.1.7 : Specifiche della lingua Java :

Se il valore p in box è true, false, un byte, un char nell’intervallo da \ u0000 a \ u007f o un numero int o short compreso tra -128 e 127, allora r1 e r2 saranno i risultati di due conversioni di boxing di p. È sempre il caso che r1 == r2.

Anche la parte di discussione delle specifiche che seguono immediatamente è interessante. In particolare, una JVM può memorizzare più valori nella cache se lo desidera, non è ansible essere certi dei risultati ottenuti:

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

Quando si esegue il boxing automatico, i numeri interi da -128 a 127 vengono memorizzati nella cache e viene restituito lo stesso object wrapper. Lo stesso con valori booleani e valori di char tra \ u0000 e \ u007F

Questo è ciò che ottieni la maggior parte del tempo, tuttavia dipende dall’implementazione di JVM.

Questo perché la boxe rende interi sotto un certo valore (128, penso) si riferiscono ad alcuni oggetti precostruiti e valori superiori a nuovi oggetti.

Autoboxing utilizza Integer.valueOf (i) , non nuovo Integer (i), per build un object di class Integer.

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

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

La class intera contiene una cache di alcune istanze usate frequentemente. L’intervallo di valori varia generalmente da JVM a JVM (a volte è anche configurabile), ma in generale il codice rilevante è qualcosa del tipo:

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

(codice da sun JDK 1.6)

questo è come internare le stringhe, dal momento che entrambe salvano la memoria e consentono l'uguaglianza dei test usando un riferimento (ad esempio == al posto di uguali )

Direi che il wrapping cerca di ridurre al minimo il numero di oggetti interi e crea solo un object che rappresenta 2 anche di risparmiare memoria.

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

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