2012-10-27 16 views
29

Nie jestem w stanie zrozumieć, jak działa Java Constant Pool for Integer.Dlaczego zachowanie puli stałej Integer zmienia się na 127?

Rozumiem zachowanie ciągów znaków, a tym samym jestem w stanie usprawiedliwić się, że jest tak samo w przypadku całek całkowitych.

Tak, dla liczb całkowitych

Integer i1 = 127; 
Integer i2 = 127; 
System.out.println(i1==i2); // True 

&

Integer i1 = new Integer(127); 
Integer i2 = new Integer(127); 
System.out.println(i1==i2); // False 

Aż tu wszystko dzieje się w mojej głowie.

Co ja nie jestem w stanie strawić to, że zachowuje się inaczej, kiedy zwiększyć całkowitą od 127. Takie zachowanie zmian po 127, poniżej jest kod snippet

Integer i1 = 128; 
Integer i2 = 128; 
System.out.println(i1==i2); // False. WHY????? 

Czy ktoś mógłby mi pomóc to zrozumieć?

+0

http://stackoverflow.com/questions/1700081/why-does-128-128-return-false-but-127-127-return-true-when-converting-to -integ? lq = 1 –

Odpowiedz

35

Nie, stała pula numerów nie działa w ten sam sposób jak dla ciągów. W przypadku łańcuchów internowane są tylko stałe kompilacji - podczas gdy dla typów otoki dla typów całkowitych, każda operacja boksu będzie zawsze używać puli, jeśli ma zastosowanie dla tej wartości. Na przykład:

int x = 10; 
int y = x + 1; 
Integer z = y; // Not a compile-time constant! 
Integer constant = 11; 
System.out.println(z == constant); // true; reference comparison 

JLS gwarantuje mały zakres połączonych wartości, ale implementacje mogą wykorzystywać szerszy zakres, jeśli chcą.

Należy zauważyć, że chociaż nie jest to zagwarantowane, każda realizacja Szukałem w zastosowaniach Integer.valueOf do wykonywania operacji bokserskie - dzięki czemu można uzyskać ten sam efekt bez pomocy językowej:

Integer x = Integer.valueOf(100); 
Integer y = Integer.valueOf(100); 
System.out.println(x == y); // true 

Od section 5.1.7 of the JLS:

Jeśli wartość p jest ramką to prawda, fałsz, bajt lub znak w zakresie od \ u0000 do \ u007f lub int lub krótki numer między -128 a 127 (włącznie), to niech r1 i r2 będą wyniki dowolnych dwóch konwersji bokserskich s. Zawsze jest tak, że r1 == r2.

Idealnie boksowanie danej prymitywnej wartości p zawsze dawało identyczne odniesienie. W praktyce może to nie być możliwe przy użyciu istniejących technik implementacji. Powyższe zasady są pragmatycznym kompromisem. Ostatnia klauzula powyżej wymaga, aby pewne wspólne wartości zawsze były zapakowane w nieodróżnialne obiekty. Implementacja może je buforować, leniwie lub niecierpliwie. W przypadku innych wartości formuła ta nie akceptuje żadnych założeń dotyczących tożsamości pudełkowych wartości w części programatora. Umożliwiłoby to (ale nie wymagało) współużytkowanie niektórych lub wszystkich tych odniesień.

Zapewnia to, że w większości przypadków zachowanie będzie pożądane, bez nakładania nadmiernej kary za wydajność, zwłaszcza na małych urządzeniach. Implementacje o mniejszej ilości pamięci mogą na przykład buforować wszystkie wartości char i short, a także wartości int i long w zakresie od -32K do + 32K.

14

Java utrzymuje Integer basen z -128 do 127

Deklarowanie Integer jak poniżej

Integer i1 = 127; 

Skutkuje do

Integer i1 = Integer.valueOf(127); 

Więc co tak naprawdę dzieje się na pierwszym przypadku jest

Integer i1 = 127;<---Integer.valueOf(127); 
Integer i2 = 127;<---Integer.valueOf(127);<---Same reference as first 

z kodu źródłowego Integer dla klasy valueOf metody

public static Integer valueOf(int i) { 
    if(i >= -128 && i <= IntegerCache.high) 
     return IntegerCache.cache[i + 128]; 
    else 
     return new Integer(i); 
} 

Więc masz samego odniesienia, jeżeli wartość jest między -128 do 127 i zadzwonić valueOf indziej po prostu zwraca new Integer(i)

A ponieważ odniesienia jest sam swoje Operator == działa dla liczb całkowitych zwróconych przez valueOf między tym zakresem.

+2

+1 za podanie wartości Integer.valueOf(). Inne odpowiedzi zdają się myśleć, że to tylko magia. – EJP

7

Java buforuje obiekty całkowite w zakresie -128 to 127. Tak więc, gdy spróbujesz przypisać wartość w tym zakresie do obiektu wrapper, operacja boxing wywoła metodę Integer.valueOf, a następnie przypisze odniesienie do obiektu już w puli.

Z drugiej strony, jeśli przypiszesz wartość spoza tego zakresu do typu odniesienia wrapper, utworzy nowy obiekt Integer dla tej wartości. I stąd, porównując reference dla Integer przedmiotów o wartości spoza tego zakresu daje false

Więc

Integer i = 127; --> // Equivalent to `Integer.valueOf(127)` 
Integer i2 = 127; 

// Equivalent to `Integer.valueOf(128)` 
// returns `new Integer(128)` for value outside the `Range - [-128, 127]` 
Integer i3 = 128; 
Integer i4 = 128; 

System.out.println(i == i2); // true, reference pointing to same literal 
System.out.println(i3 == i4); // false, reference pointing to different objects 

Jednak po utworzeniu instancji całkowite pomocą new operatora, nowy obiekt zostanie utworzony na Sterta. Więc

Integer i = new Integer(127); 
Integer i2 = new Integer(127); 

System.out.println(i == i2); // false 
+0

Twoje porównanie z i3 do i4 jest niepoprawne, ponieważ używasz 'int' zamiast' Integer'. –

+0

@ JonSkeet. O! Przepraszam. Powinienem był mieć "Integer" we wszystkich czterech miejscach. Dokona edycji. Dzięki za wskazanie :) –

+0

Odpowiedź jest w zasadzie niepoprawna. Java nie "cache literałów całkowitych". Java buforuje obiekty * Integer * od -128 do 127 *, jeśli wywołasz Integer.valueOf(), aby je uzyskać, * co dzieje się w auto boxingu, ale nie w kodzie OP, dlatego nie daje oczekiwanej odpowiedzi . – EJP

Powiązane problemy