public static void main(String[] args) { Integer inPoolBoxed1 = 127; Integer inPoolBoxed2 = 127; System.out.println(inPoolBoxed1 == inPoolBoxed2); Integer outPoolBoxed1 = 1270; Integer outPoolBoxed2 = 1270; System.out.println(outPoolBoxed1 == outPoolBoxed2); }Ogni tanto mi capita di mostrare questo semplice metodo main che fa la comparazione tra i riferimenti di due coppie di oggetti Interger ottenuti per boxing di un valore primitivo.
Alla domanda: "cosa stamperanno le system.out?" la risposta è, il più delle volte, "false" e "false", con la spiegazione che si sono istanziati quattro nuovi oggetti che avranno ciascuno un riferimento differente. La logica non fa una piega.
Eseguendo il codice, però, molti hanno una sorpresa. Viene stampato rispettivamente "true" e "false". Come può essere? Eppure sono oggetti diversi! E perché il primo caso è diverso dal secondo?
La verità è che non sono oggetti diversi, almeno nel primo caso.
Infatti, allo scopo di risparmiare memoria la JVM (che, ricordo, fu originariamente progettata per essere eseguita su dispositivi con memoria MOLTO limitata) gli int, gli short, i byte, i char e i boolean che vengono creati per autoboxing vengono messi in un pool e riutilizzati quando serve. Questo funziona solo per valori che, all'epoca si pensava fossero usati più spesso, ossia quelli da -128 a 127 per i numerici, true e false per i boolean e da \u0000 a \u007f (che numericamente è 127). Per questo motivo un valore come 1270 non viene messo nel pool e riutilizzato, ma creato ogni volta.
Ora, dal momento che comparare oggetti con l'operatore == non capita spesso e, in genere, non si dovrebbe fare per testare l'uguaglianza del valore di due oggetti, è difficile imbattersi in questo tipo di casistiche, ma, nel caso vi capiti siete avvertiti, la JVM non è posseduta dal demonio.
PS: il comportamento torna ad essere quello standard e "prevedibile" se invece di creare gli Integer (o Short, Byte...) tramite boxing di tipi primitivi, si usa il normale operatore new.
0 commenti :
Posta un commento