Witam w kolejnym odcinku Java Killers. Odcinek ten pojawić się miał troszkę później (jest na tyle ciekawy, że chciałem z nim poczekać do połowy maja, aż wszyscy bez wyjątku wytrzeźwieją po weekendzie majowym), ale ponieważ pojawił się na jdn.pl jego preview w komentarzach do jednego z poprzednich JK, postanowiłem umieścić go teraz, aby pozostał jeszcze jakiś element zaskoczenia. A więc, aby jak zwykle nie przedłużać wstępów, zabierzmy się do dzieła.
Dziś porównamy sobie obiekty typu Integer, ot takie najzwyklejsze ==. Przejdźmy więc do kodu:
1 package javakillers.part004;
2
3 /**
4 *
5 * @author pawel
6 */
7 public class Main
8 {
9 public static void main(String[] args)
10 {
11 Main m = new Main();
12 m.run();
13 }
14 public void run()
15 {
16 check(2, 2);
17 check(2000, 2000);
18 }
19
20 void check(Integer a,Integer b)
21 {
22 System.out.print((a==b) + " ");
23 }
24 }
25
26
Proste prawda? No więc teraz pytanie, jaka będzie odpowiedź? Standardowo 4 możliwe odpowiedzi do wyboru:
A) true true
B) false false
C) false true
D) true false
Okazuje się, że prawidłowa odpowiedź to D) true false. Ale, że co? Jak to możliwe?? Ja rozumiem A lub B ale, że D? Żeby zrozumieć czemu odpowiedź jest taka a nie inna należy zajrzeć do specyfikacji, autoboxing opisany jest w JSR-201, gdzie w rozdziale piątym czytamy:
"If the value p being boxed is true, false, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2."
Wszystko rozchodzi się o zarządzanie pamięcią. Jeśli jakąś wartość prymitywną możemy zmieścić w jednym bajcie (czyli wszystkie boolean, byte oraz char'y od \u0000 do \u007f oraz short i int w przedziale -128 do 127), wtedy boxowane obiekty znajdują się w jednym miejscu pamięci, a więc sprawdzanie ich referencji da nam zawsze true.
Miażdzące prawda?
Pytanie teraz, jak się przed tym chronić? Zasada podstawowa nakazuje przede wszystkim sprawdzanie obiektów poprzez sprawdzanie ich zawartości (używając metody equals), a nie referencji. Takie podejście uratuje Wam nie raz życie i sprawdza się nie tylko przy zabawach z obiektami typu wrapper.
Druga nauka to taka, że jak okazuje się żadna książka nigdy nie zastąpi nam do końca specyfikacji czy dokumentacji. Polecam Unixową mantrę RTFM, chociaż z drugiej strony, kto ma na to czas ;)
6 komentarzy:
Znowu pudło. Zaznaczając odpowiedź wiedziałem, że to na pewno nie to - było by to zbyt banalne. Także następnym razem wybiorę najmniej logiczną odpowiedź, wtedy powinno się udać ;-)
Ten trik akurat znałem. Jak byłem mało obyty z programowaniem, to kilka razy się na tym wyłożyłem - podczas testów wszystko działało OK, a nagle w produkcji wychodziły buraki, bo sekwencja, z której był ustawiany klucz główny w bazie przekroczyła 128.
juz miesiac temu Ci o tym mowilem :P
a dowiedzialem sie od Piotrka z PM.
pozdrawiam
cholera, zaczynam sie czuc jak uczniak... za co ja mam ten SCJP? ;D
Szczerze mówiąc jak dla mnie brakuje odpowiedzi, że kod się nie skompiluje. :)
Czy może jest jakaś autopromocja prymitywa do Integera??
czyzby choidzlo ci o autoboxing od javy 1.5 ? ;)
Prześlij komentarz