public class Test { public static void main(String[] args) { Integer i = 10, j = 10, k = 1000, l = 1000; System.out.println(i == j); System.out.println(k == l); } }
public class Test { public static void main(String[] args) { Integer i = 10, j = 10, k = 1000, l = 1000; System.out.println(i == j); System.out.println(k == l); } }
Takie zachowanie bierze się z faktu istnienia mechanizmu Cache w celu optymalizacji wydajności np. pętle "for" dla niewielkich ilości iteracji, proste obliczenia itp. Dla małych liczb całkowitych przechowywanych w Integer, Short, a nawet Long (odpakowana wartość musi się mieścić w 8 bitach ze znakiem), czyli dla zakresu od -128 do +127, wartości te są trzymane właśnie w Cache, i w wyniku optymizacji tak są ustawiane referencje, aby wskazywały na ten sam obiekt w pamięci.
Operator == w przykładzie:
Integer i = 10, j = 10; System.out.println(i == j);
jest w istocie porównaniem referencji do dwóch obiektów typu Integer - w tym przypadku, dzięki optymizacji, te referencje są równe. Operator nie porównuje tu wartości "zaszytej" dzięki mechanizmowi autoboxingu, w środku Integera.
Na marginesie, używając porównania typów prostych np.:
int i = 1000, j = 1000; System.out.println(i==j);
zawsze dostaniemy wartość true, ponieważ dla typów prostych (int, short, long) operator == porównuje wartość zmiennej.
Możesz też zerknąć do implementacji klasy Integer, a szczególnie do kodu metody valueOf(...) i klasy zagnieżdżonej IntegerCache - tam widać, że klasa IntegerCache zawiera tablicę Integerów.
Cytuję komentarz:
Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS.
Odbiegając trochę od tematu, warto zauważyć, że takich optymalizacji jest w Javie więcej. Przykładem może być klasa java.lang.String. Podobnie jak klasy opakowujące typy proste jest ona niezmienna (immutable). Dzięki temu obiekty tworzone poprzez literały są odkładane w puli i przed utworzeniem nowego obiektu, najpierw sprawdzane jest, czy nie ma go w puli. W takim przypadku tworzona jest tylko nowa referencja wskazująca ten sam obiekt. Stąd porównanie:
String s1 = "abc"; String s2 = "abc"; System.out.println(s1 == s2);
zwróci wartość true.
Inaczej sprawa przedstawia się, gdy użyjemy jawnie konstruktora. Wtedy:
String s1 = "abc"; String s2 = new String("abc"); System.out.println(s1 == s2);
porównanie referencji zwróci wartość false (zaś metoda equals - wartość true).