Integer pool. ISeeBugs.plInteger Pool

O tym, że Stringi są przechowywane w String Pool prawie każdy kto ma styczność z Javą słyszał, tak samo o tym, żeby obiekty referencyjne porównywać metodą equals a nie za pomocą „==”. Ale czy wszyscy słyszeli o Integer Pool i dlaczego to ważne?

Mechanizm pool

W JVM obiekty które twórcy uważają za często używane są przechowywane w specjalnych pulach aby oszczędzić pamięć i poprawić wydajność aplikacji.

Po za najbardziej znaną pulą Stringów istnieją jeszcze 3 pule dla klas opakowujących(Wrapper Class). Łącznie istnieją następujące poole:

  • String Pool
  • Integer Pool
  • Boolean Pool
  • Character Pool

String pool

Załóżmy, istnieje obiekt typu String o wartości np. String a = "aabbcc";. Mechanizm puli polega na tym, że przy „tworzeniu” nowego obiektu, JVM tak naprawdę nie tworzy nowego obiektu tylko przypisuje referencje do już utworzonego obiektu. W przypadku utworzenia obiektu String b = "aabbcc" obydwa obiekty będą wskazywały na to samo miejsce w pamięci JVM. W takim przypadku porównywanie tych obiektów za pomocą „==” oraz equals zwróci nam w obu przypadkach true. „==” zwróci nam true ponieważ porównanie to sprawdza czy referencje porównywanych obiektów wskazują na ten sam obiekt. Porównanie equals również zwróci nam true ponieważ funkcja porównuje wartości które są jednakowe.

Kod:

String a = "aabbcc";
String b = "aabbcc";
boolean result = a.equals(b);
System.out.printf("Is a equals b?: %b %n", result);

String c = "aabbcc";
String d = "aabbcc";
result = c == d;
System.out.printf("Is c equals c?: %b %n", result);

Wynik:

Is a equals b?: true 
Is c equals c?: true 

Nie mogę tu nie wspomnieć, że w przypadku tworzenia nowego Stringa przy pomocy słowa kluczowego new nie trafi on do puli Stringów tylko na stertę obiektów i w takim przypadku porównanie obiektów przy pomocy „==” zwróci false.

Kod:

String a = "aabbcc";
String b = "aabbcc";
boolean result = a.equals(b);
System.out.printf("Is a equals b?: %b %n", result);

String c = "aabbcc";
String d = new String("aabbcc");
result = c == d;
System.out.printf("Is c equals c?: %b %n", result);

Wynik:

Is a equals b?: true 
Is c equals c?: false 

Integer pool

O ile o powyższym mechanizmie każdy kto pracuje z Javą jest zaznajomiony to o pozostałych pulach nie wszyscy słyszeli. Największe konsekwencje dla naszego kodu może mieć nie znajomośc mechanizmu Integer Pool i prawidłowego porównywania obiektów typu Integer. Automatycznie chcielibyśmy porównywać obiekty Integer w taki sam sposób jak typy prymitywne to znaczy za pomocą znaków równości „==”. Jest to błąd który może powodować błędne działanie programu a ponadto jest trudny do wychwycenia.

W Puli Integerów przechowywane są wartości od -128 do 127 to znaczy, że dla tych wartości nie są tworzone nowe obiekty w pamięci, tylko tworzone obiekty wskazują poprzez swoją referencje na już istniejące. Poniżej oraz powyżej tych wartości Integery nie odwołują się do obiektów z puli Integerów, lecz są tworzone obiekty które nie mają wspólnych referencji. Przeanalizujmy analogiczny przykład jaki był w przypadku Stringów.

Kod:

Integer a = 127;
Integer b = 127;
boolean result = a.equals(b);
System.out.printf("Is a equals b?: %b %n", result);

Integer c = 127;
Integer d = 127;
result = c == d;
System.out.printf("Is c equals d?: %b %n", result);
Is a equals b?: true 
Is c equals d?: true 

W powyższym przykładzie wszystkie obiektu znajdują się w puli Integerów więc zarówno porównanie ich za pomocą equals jak i „==” zwróci nam true. Ale ciekawiej dzieje się kiedy wyjdziemy poza zakres puli Integerów.

Kod:

Integer a = 128;
Integer b = 128;
boolean result = a.equals(b);
System.out.printf("Is a equals b?: %b %n", result);

Integer c = 128;
Integer d = 128;
result = c == d;
System.out.printf("Is c equals d?: %b %n", result);

Wynik:

Is a equals b?: true 
Is c equals d?: false 

Jeżeli wyjdziemy poza pulę Integerów JVM tworzy niezależne od siebie obiekty o wartości „128”. W tym przypadku porównanie wartości za pomocą equals zwróci oczekiwany wynik „true”, lecz porównanie referencji za pomocą „==” zwróci na false. Dlatego tak ważne jest aby wszystkie obiekty referencyjne porównywać za pomocą metody equals, nawet wrapper class.

Podsumowanie

Dowiedzieliśmy się dlaczego obiekty typu Integer powinniśmy zawsze porównywać metodą equals a nie za pomocą”==”, oraz zapoznaliśmy się z mechanizmem Pool w JVM.

A co zwróci nam porównywanie typu prymitywnego int z Integer za pomocą equals oraz „==”? To już zostawiam Tobie i zachęcam do zabawy z kodem 🙂

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *