Czemu czasami porównanie obiektu typu Integer za pomocą „==” działa?

Ciężko na początku swojej nauki zrozumieć czemu porównywanie za pomocą operatora == jest nie do końca poprawne. Pytanie dotyczące porównywania Stringa na rozmowa rekrutacyjnych pojawia się równie często co pytanie o to czym jest interfejs.

Staramy wyrobić sobie taką intuicję, że o ile nie są to typy prymitywne (int, boolean..) to najlepszym rozwiązaniem będzie porównywanie obiektów za pomocą specjalnych metod – equals czy compareTo. Ale okazuje się, że czasami jednak to „naiwne” porównanie obiektów za pomocą operatora == działa i wtedy warto się zastanowić – czemu?

Sprawdźmy co siedzi w źródle

Zacznijmy może od przypomnienia, że konstrukcja:

Integer a = 128;

Jest przez kompilator konwertowana do:

Integer a = Integer.valueOf(128);

Jest to dosyć ważne, bo teraz wiemy gdzie szukać – zobaczmy co się kryje w metodzie valueOf:

Implementacja metody valueOf(int i)

Okazuje się, że valueOf robi coś więcej niż tylko opakowanie naszego inta w obiekt Integer. To też poniekąd tłumaczy sytuację, która widzimy tutaj:

Nie zawsze Integer 127 == Integer 127

Wracając do implementacji valueOf – jeżeli nasza wartość znajduje się w odpowiednim przedziale (domyślnie jest to: [-128, 127]) to zwrócona zostanie wartość z cache znajdującego się w statycznej klasie IntegerCache. Ten przedział możemy bez problemu zmienić ustawiając w konfiguracji VM zmienną -XX:AutoBoxCacheMax=rozmiar

Na zakończenie.. W jednym z projektów przy którym miałem okazję pracować jakiś czas temu, znalazłem sporo takich miejsc w których obiekty typu Integer porównywane są za pomocą ==. W momencie gdy poruszyłem ten temat, przedstawiając swoje obawy, dostałem odpowiedź – Przecież to działa, bo przy porównywaniu poprzez == jest unboxing. 🙂 I rzeczywiście to działało, ale powód był inny – te liczby, które zazwyczaj pod tymi zmiennymi się kryły, były po prostu bardzo małe.