Właśnie zobaczyłem kod podobny do tego:
public class Scratch
{
public static void main(String[] args)
{
Integer a = 1000, b = 1000;
System.out.println(a == b);
Integer c = 100, d = 100;
System.out.println(c == d);
}
}
Po uruchomieniu ten blok kodu zostanie wydrukowany:
false
true
Rozumiem, dlaczego pierwszy jest taki false
: ponieważ dwa obiekty są oddzielnymi obiektami, więc ==
porównuje odniesienia. Ale nie mogę się dowiedzieć, dlaczego wraca druga instrukcja true
? Czy jest jakaś dziwna reguła autoboxu, która zaczyna działać, gdy wartość całkowita jest w pewnym zakresie? Co tu się dzieje?
java
autoboxing
Joel
źródło
źródło
Odpowiedzi:
true
Linia jest faktycznie gwarantowany przez specyfikację języka. Z sekcji 5.1.7 :Dyskusja toczy się dalej, sugerując, że chociaż twoja druga linia wyjścia jest gwarantowana, pierwsza nie (zobacz ostatni cytowany akapit poniżej):
źródło
valueOf
metody klasy box (likeInteger.valueOf(int)
). Interesujące jest to, że JLS definiuje dokładne usuwanie cukru z opakowania - używającintValue()
et al - ale nie definiuje usuwania cukru z opakowania.Integer
niż przez oficjalnepublic
API, czyli wywołanieintValue()
. Ale istnieją inne możliwe sposoby uzyskaniaInteger
instancji dlaint
wartości, np. Kompilator może wygenerować kod przechowujący i ponownie wykorzystujący wcześniej utworzoneInteger
instancje.Wynik:
Tak, pierwszy wynik jest tworzony do porównania odniesienia; „a” i „b” - to są dwa różne odniesienia. W punkcie 1 faktycznie tworzone są dwa odniesienia, które są podobne do -
Drugie wyjście jest generowane, ponieważ
JVM
próbuje zaoszczędzić pamięć, gdyInteger
mieści się w zakresie (od -128 do 127). W punkcie 2 nie jest tworzone nowe odniesienie typu Integer dla „d”. Zamiast tworzyć nowy obiekt dla zmiennej referencyjnej typu Integer „d”, przypisuje się ją tylko do utworzonego wcześniej obiektu, do którego odwołuje się „c”. Wszystko to jest wykonywane przezJVM
.Te zasady oszczędzania pamięci dotyczą nie tylko liczby całkowitej. ze względu na oszczędzanie pamięci, dwie instancje następujących obiektów opakowujących (utworzonych przez opakowanie) zawsze będą ==, gdzie ich pierwotne wartości są takie same -
\u007f
(7f to 127 dziesiętnie)źródło
Long
ma również pamięć podręczną z tym samym zakresem coInteger
.Obiekty całkowite w pewnym zakresie (myślę, że może od -128 do 127) są buforowane i ponownie używane. Liczby całkowite spoza tego zakresu za każdym razem otrzymują nowy obiekt.
źródło
java.lang.Integer.IntegerCache.high
właściwości. Ciekawe, że Long nie ma takiej opcji.Tak, istnieje dziwna reguła autoboxu, która działa, gdy wartości mieszczą się w pewnym zakresie. Kiedy przypisujesz stałą do zmiennej Object, nic w definicji języka nie mówi, że nowy obiekt musi zostać utworzony. Może ponownie wykorzystać istniejący obiekt z pamięci podręcznej.
W rzeczywistości JVM zazwyczaj przechowuje w tym celu pamięć podręczną małych liczb całkowitych, a także wartości, takich jak Boolean.TRUE i Boolean.FALSE.
źródło
Domyślam się, że Java przechowuje pamięć podręczną małych liczb całkowitych, które są już „zapakowane”, ponieważ są one bardzo powszechne i oszczędza mnóstwo czasu na ponowne wykorzystanie istniejącego obiektu niż na utworzenie nowego.
źródło
To interesująca kwestia. W książce Efektywna Java sugeruje, aby zawsze nadpisywać równości dla własnych klas. Ponadto, aby sprawdzić równość dwóch instancji obiektów klasy Java, należy zawsze używać metody equals.
zwroty:
źródło
W Javie boks działa w zakresie od -128 do 127 dla liczby całkowitej. Jeśli używasz liczb z tego zakresu, możesz je porównać z operatorem ==. W przypadku obiektów typu Integer spoza zakresu musisz użyć równości.
źródło
Bezpośrednie przypisanie literału int do odwołania Integer jest przykładem automatycznego pakowania, w którym wartość literału do kodu konwersji obiektu jest obsługiwana przez kompilator.
Tak więc podczas fazy kompilacji kompilator konwertuje
Integer a = 1000, b = 1000;
doInteger a = Integer.valueOf(1000), b = Integer.valueOf(1000);
.Jest to więc
Integer.valueOf()
metoda, która faktycznie daje nam obiekty będące liczbami całkowitymi, a jeśli spojrzymy na kod źródłowyInteger.valueOf()
metody, wyraźnie widać, że metoda buforuje obiekty typu integer w zakresie od -128 do 127 (włącznie).Dlatego zamiast tworzyć i zwracać nowe obiekty całkowite,
Integer.valueOf()
metoda zwraca obiekty typu Integer z wewnętrznego,IntegerCache
jeśli przekazany literał int jest większy niż -128 i mniejszy niż 127.Java buforuje te obiekty liczb całkowitych, ponieważ ten zakres liczb całkowitych jest często używany w codziennym programowaniu, co pośrednio oszczędza trochę pamięci.
Pamięć podręczna jest inicjowana przy pierwszym użyciu, gdy klasa zostanie załadowana do pamięci ze względu na blok statyczny. Maksymalny zakres pamięci podręcznej można kontrolować za pomocą
-XX:AutoBoxCacheMax
opcji JVM.Takie zachowanie buforowania nie dotyczy tylko obiektów Integer, podobnie Integer.IntegerCache mamy także
ByteCache, ShortCache, LongCache, CharacterCache
dlaByte, Short, Long, Character
odpowiednio.Możesz przeczytać więcej na temat mojego artykułu Java Integer Cache - Why Integer.valueOf (127) == Integer.valueOf (127) Is True .
źródło
W Javie 5 wprowadzono nową funkcję oszczędzającą pamięć i poprawiającą wydajność obsługi obiektów typu Integer. Obiekty całkowite są buforowane wewnętrznie i ponownie używane za pośrednictwem tych samych obiektów, do których istnieją odniesienia.
Ma to zastosowanie do wartości całkowitych z zakresu od –127 do +127 (maksymalna wartość całkowita).
Buforowanie typu Integer działa tylko w przypadku autoboxingu. Obiekty całkowite nie będą buforowane, gdy zostaną zbudowane przy użyciu konstruktora.
Aby uzyskać więcej informacji, przejdź przez poniższy Link:
Całkowita pamięć podręczna w szczegółach
źródło
Jeśli sprawdzimy kod źródłowy
Integer
obeject, znajdziemy źródłovalueOf
metody tak:co może wyjaśnić, dlaczego
Integer
obiekty, które są w zakresie od -128 (Integer.low
) do 127 (Integer.high
), są tymi samymi obiektami, do których istnieją odniesienia podczas autoboxingu. I widzimy, że istnieje klasaIntegerCache
zajmuje sięInteger
tablicą pamięci podręcznej, która jest prywatną statyczną wewnętrzną klasąInteger
klasy.Jest jeszcze jeden interesujący przykład, który może pomóc nam zrozumieć tę dziwną sytuację:
źródło