Wiem, że jest to prawdopodobnie bardzo głupie, ale wiele miejsc twierdzi, że klasa Integer w Javie jest niezmienna, ale następujący kod:
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
Wykonuje się bez żadnych problemów dając (oczekiwany) wynik 6. W efekcie wartość a uległa zmianie. Czy to nie znaczy, że liczba całkowita jest zmienna? Drugie pytanie i trochę offtopic: „Niezmienne klasy nie potrzebują konstruktorów kopiujących”. Czy ktoś chce wyjaśnić, dlaczego?
java
immutability
mutable
K.Steff
źródło
źródło
Odpowiedzi:
Niezmienność nie oznacza, że
a
nigdy nie może równać się innej wartości. Na przykładString
jest niezmienna, ale nadal mogę to zrobić:str
nie został zmieniony,str
jest teraz całkowicie nowo utworzonym obiektem, tak jak TwójInteger
. Tak więc wartośća
nie uległa mutacji, ale została zastąpiona przez zupełnie nowy obiekt tjnew Integer(6)
.źródło
+=
operacji.Integer.valueOf(int)
i ta metoda utrzymuje pamięć podręcznąInteger
obiektów. Więc wynik+=
naInteger
zmiennej może być obiektem, który wcześniej istniał (albo może to być nawet ten sam obiekt ... w przypadkua += 0
).a
jest "odniesieniem" do jakiejś liczby całkowitej (3), twój skróta+=b
naprawdę oznacza robienie tego:Więc nie, liczby całkowite nie są zmienne, ale zmienne, które na nie wskazują, to *.
* Można mieć niezmienne zmienne, są one oznaczone słowem kluczowym
final
, co oznacza, że odniesienie nie może się zmienić.źródło
Możesz określić, że obiekt zmienił się za pomocą
System.identityHashCode()
(lepszym sposobem jest użycie zwykłego,==
ale nie jest tak oczywiste, że zmieniło się odniesienie, a nie wartość)wydruki
Możesz zobaczyć, że podstawowy „id” obiektu,
a
do którego odwołuje się, zmienił się.źródło
Na zadane pierwsze pytanie:
Liczba całkowita jest niezmienna, więc to, co wydarzyło się powyżej, to „a” zmieniło się na nowe odniesienie o wartości 6. Wartość początkowa 3 pozostaje bez odniesienia w pamięci (nie została zmieniona), więc może zostać usunięta.
Jeśli tak się stanie z ciągiem, pozostanie on w puli (w przestrzeni PermGen) przez dłuższy okres niż liczby całkowite, ponieważ oczekuje, że będą miały odniesienia.
źródło
Tak Liczba całkowita jest niezmienna.
A to odniesienie, które wskazuje na obiekt. Po uruchomieniu + = 3, to ponownie przypisuje A do nowego obiektu Integer z inną wartością.
Nigdy nie modyfikowałeś oryginalnego obiektu, a raczej wskazałeś odniesienie do innego obiektu.
Przeczytaj o różnicy między obiektami a odniesieniami tutaj .
źródło
Niezmienność nie oznacza, że nie można zmienić wartości zmiennej. Oznacza to po prostu, że każde nowe przypisanie tworzy nowy obiekt (przypisuje mu nowe miejsce w pamięci), a następnie zostaje mu przypisana wartość.
Aby samemu to zrozumieć, wykonaj przypisanie liczb całkowitych w pętli (z zadeklarowaną liczbą całkowitą poza pętlą) i spójrz na obiekty na żywo w pamięci.
Powodem, dla którego konstruktor kopiujący nie jest potrzebny dla niezmiennych obiektów, jest prosty zdrowy rozsądek. Ponieważ każde przypisanie tworzy nowy obiekt, z technicznego punktu widzenia język tworzy już kopię, więc nie musisz tworzyć kolejnej kopii.
źródło
Powodem jest to, że rzadko istnieje potrzeba kopiowania (lub nawet jakiegokolwiek sensu kopiowania) instancji niezmiennej klasy. Kopia obiektu powinna być „taka sama jak” oryginał, a jeśli jest taka sama, nie powinno być potrzeby jej tworzenia.
Istnieją jednak pewne podstawowe założenia:
Zakłada się, że aplikacja nie nadaje żadnego znaczenia tożsamości obiektów instancji klasy.
Zakłada, że klasa została przeciążona
equals
ihashCode
kopia instancji byłaby „taka sama jak” oryginał… zgodnie z tymi metodami.Jedno lub oba z tych założeń mogą być fałszywe, a to może uzasadniać dodanie konstruktora kopiującego.
źródło
Oto jak rozumiem niezmienne
Gdyby int mógł się zmutować, "a" wypisałoby 8, ale nie, ponieważ jest niezmienne, dlatego jest równe 3. Twój przykład jest po prostu nowym przypisaniem.
źródło
Mogę wyjaśnić, że Integer (i inne jego wyznania, takie jak Float, Short itp.) Są niezmienne za pomocą prostego przykładowego kodu:
Wynik to on Hi There 100 zamiast oczekiwanego wyniku (w przypadku gdy zarówno sb, jak i i są obiektami mutowalnymi) Hi There 1000
To pokazuje, że obiekt utworzony przez i w main nie jest modyfikowany, podczas gdy sb jest modyfikowany.
Więc StringBuilder zademonstrował zmienne zachowanie, ale nie Integer.
Więc liczba całkowita jest niezmienna. Stąd udowodnione
źródło
private void doStringBuilder(StringBuilder sb){ sb = new StringBuilder(); }
tosb
pozostaje bez zmian.private void doInteger(Integer i){ System.out.println( i == 100 ); i=1000; System.out.println( i == 100 ); }
Wynik to:
Cześć Pa 1000 5000 1000 5000 d a
Więc char jest zmienna, String Integer i int są niezmienne.
źródło