Rozważ następujący przykład.
String str = new String();
str = "Hello";
System.out.println(str); //Prints Hello
str = "Help!";
System.out.println(str); //Prints Help!
Teraz w Javie obiekty String są niezmienne. Dlaczego więc obiektowi str
można przypisać wartość „Pomoc!”. Czy nie jest to sprzeczne z niezmiennością ciągów w Javie? Czy ktoś może mi wyjaśnić dokładną koncepcję niezmienności?
Edytować:
Dobrze. Teraz rozumiem, ale tylko jedno pytanie uzupełniające. Co z następującym kodem:
String str = "Mississippi";
System.out.println(str); // prints Mississippi
str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp!
Czy to oznacza, że dwa obiekty są tworzone ponownie („Mississippi” i „M! Ss! Ss! Pp!”), A odniesienie str
wskazuje na inny obiekt po replace()
metodzie?
java
string
immutability
Lekki uchwyt
źródło
źródło
Odpowiedzi:
str
nie jest przedmiotem, to odniesienie do obiektu."Hello"
i"Help!"
są dwoma odrębnymiString
przedmiotami. W ten sposóbstr
wskazuje na ciąg. Możesz zmienić to, na co wskazuje , ale nie to, na co wskazuje .Weź ten kod, na przykład:
Teraz nie ma nic 1 moglibyśmy zrobić
s1
, które wpływają na wartośćs2
. Odnoszą się do tego samego obiektu - łańcucha"Hello"
- ale ten obiekt jest niezmienny i dlatego nie można go zmienić.Jeśli zrobimy coś takiego:
Widzimy tutaj różnicę między mutowaniem obiektu a zmianą referencji.
s2
nadal wskazuje na ten sam obiekt, na który początkowos1
wskazywaliśmy. Ustawianies1
się"Help!"
tylko zmienia odniesienia , podczas gdyString
obiekt pierwotnie mowa pozostaje niezmieniona.Gdyby łańcuchy były zmienne, moglibyśmy zrobić coś takiego:
Edytuj, aby odpowiedzieć na edycję OP:
Jeśli spojrzysz na kod źródłowy String.replace (char, char) (dostępny również w src.zip w katalogu instalacyjnym JDK - wskazówką jest, aby szukać tam, gdy zastanawiasz się, jak coś naprawdę działa), możesz zobaczyć, co robi to następująco:
oldChar
w bieżącym ciągu znajduje się jedno lub więcej wystąpień , wykonaj kopię bieżącego ciągu, w którym wszystkie wystąpieniaoldChar
zostaną zastąpionenewChar
.oldChar
nie ma go w bieżącym ciągu, zwróć bieżący ciąg.Tak,
"Mississippi".replace('i', '!')
tworzy nowyString
obiekt. Ponownie, następujące są następujące:Na razie twoją pracą domową jest sprawdzenie, co robi powyższy kod, jeśli zmienisz
s1 = s1.replace('i', '!');
nas1 = s1.replace('Q', '!');
:)1 Faktycznie, to jest możliwe, aby mutować strun (i innych niezmiennych obiektów). Wymaga refleksji i jest bardzo, bardzo niebezpieczny i nigdy nie należy go używać, chyba że faktycznie chcesz zniszczyć program.
źródło
Obiekt, który się
str
odwołuje, może się zmienić, aleString
same obiekty nie mogą.String
Obiektów zawierających ciąg znaków"Hello"
i"Help!"
nie może zmieniać ich wartości, stąd są one niezmienne.Niezmienność
String
obiektów nie oznacza, że odniesienia do obiektu nie mogą ulec zmianie.Jednym ze sposobów, w jaki można zapobiec
str
zmianie odwołania, jest zadeklarowanie go jakofinal
:Teraz próba przypisania innej
String
doSTR
spowoduje błąd kompilacji.źródło
str
nie „obiekt” to odniesienie do obiektu. JeśliString str = "Hello";
poString anotherReference = str;
tym nie masz 2 obiektów String, masz jeden obiekt (dosłownie „Hello”) i 2 odniesienia do niego (str
ianotherReference
).Light_handle Polecam lekturę Rozmiar miseczki - opowieść o zmiennych i wartościach proszę o podanie (Rozmiar miseczki kontynuowany) . To bardzo pomoże w czytaniu powyższych postów.
Przeczytałeś je? Tak. Dobry.
Tworzy to nowy „pilot” o nazwie „
str
” i ustawia wartośćnew String()
(lub""
).np. w pamięci tworzy to:
To następnie zmienia pilot „
str
”, ale nie modyfikuje oryginalnego ciągu""
.np. w pamięci tworzy to:
To następnie zmienia pilot „
str
”, ale nie modyfikuje oryginalnego ciągu""
lub obiektu, na który obecnie wskazuje pilot.np. w pamięci tworzy to:
źródło
Rozbijmy to na części
Ta instrukcja tworzy ciąg zawierający hello i zajmuje miejsce w pamięci, tj. W stałej puli ciągów i przypisuje go do obiektu odniesienia s1
Ta instrukcja przypisuje ten sam ciąg hello do nowego odwołania s2
Oba odniesienia wskazują na ten sam ciąg, więc wypisz tę samą wartość, jak poniżej.
Chociaż String jest niezmienny , przypisanie może być możliwe, więc s1 będzie teraz odnosił się do nowego stosu wartości .
Ale co z obiektem s2, który wskazuje na cześć , będzie taki, jaki jest.
Ponieważ String jest niezmienny Java Virtual Machine nie pozwoli nam modyfikować łańcucha s1 za pomocą jego metody. Stworzy wszystkie nowe obiekty String w puli w następujący sposób.
Zauważ, że jeśli String byłby zmienny, to wynik byłby
Teraz możesz być zaskoczony, dlaczego String ma takie metody, jak concat () do modyfikacji. Poniższy fragment usunie zamieszanie.
Tutaj przypisujemy zmodyfikowaną wartość ciągu z powrotem do odwołania s1 .
Właśnie dlatego Java zdecydowała, że String będzie klasą końcową. W przeciwnym razie każdy może modyfikować i zmieniać wartość łańcucha. Mam nadzieję, że to trochę pomoże.
źródło
Obiekt łańcucha, do którego najpierw odwołano,
str
nie został zmieniony, jedyne, co zrobiłeś, tostr
odwołanie się do nowego obiektu łańcucha.źródło
Ciąg nie zmieni się, odniesienie do niego ulegnie zmianie. Mylisz niezmienność z pojęciem
final
pól. Jeśli pole zostanie zadeklarowane jakofinal
, po przypisaniu nie można go ponownie przypisać.źródło
Jeśli chodzi o zastąpienie części pytania, spróbuj:
źródło
Chociaż Java próbuje to zignorować,
str
jest niczym więcej niż wskaźnikiem. Oznacza to, że kiedy piszesz po raz pierwszystr = "Hello";
, tworzysz obiekt, którystr
wskazuje. Podczas zmiany przypisaniastr
przez pisaniestr = "Help!";
tworzony jest nowy obiekt, a stary"Hello"
obiekt jest zbierany na śmiecie, gdy tylko Java ma na to ochotę .źródło
Niezmienność oznacza, że wartość tworzonego obiektu nie może się zmienić, nigdy nie można zmienić „Cześć” w „Pomoc!”.
Zmienna str jest odniesieniem do obiektu, gdy przypisujesz nową wartość do str, nie zmieniasz wartości obiektu, do którego się odwołuje, odwołujesz się do innego obiektu.
źródło
Klasa string jest niezmienna i nie można zmienić wartości niezmiennego obiektu. Ale w przypadku Ciągu, jeśli zmienisz wartość ciągu, spowoduje to utworzenie nowego ciągu w puli ciągów, a następnie odniesienie ciągu do tej wartości, a nie do starszej. w ten sposób ciąg jest niezmienny. Weźmy swój przykład,
utworzy jeden ciąg „Mississippi” i doda go do puli ciągów, więc teraz str wskazuje na Mississippi.
Ale po powyższej operacji utworzony zostanie kolejny ciąg „M! Ss! Ss! Pp!” i zostanie dodany do puli ciągów. a teraz str wskazuje na M! ss! ss! pp !, a nie Mississippi.
w ten sposób, kiedy zmienisz wartość obiektu string, utworzy on jeszcze jeden obiekt i doda go do puli stringów.
Miejmy jeszcze jeden przykład
ta powyżej trzy linie doda trzy obiekty łańcucha do puli łańcuchów.
1) Witaj
2) Świat
3) HelloWorld
źródło
Posługiwać się:
Jeśli widzisz tutaj, używam
concat
metody, aby zmienić oryginalny ciąg, czyli „Nowy ciąg” z ciągiem „Dodany ciąg”, ale nadal otrzymałem wynik jak poprzednio, stąd dowodzi, że nie można zmienić odwołania do obiektu klasy String, ale jeśli zrobisz to przez klasę StringBuilder, zadziała. Jest wymieniony poniżej.źródło
Jak powiedział Linus Tolvards:
Spójrz na to:
Dane wyjściowe to
Pamiętaj więc o dwóch rzeczach:
źródło
Dla tych, którzy zastanawiają się, jak przełamać niezmienność String w Javie ...
Kod
Wynik
źródło
Sznurek jest niezmienny . Co oznacza, że możemy zmienić tylko odniesienie .
źródło
W Javie obiekty są ogólnie dostępne przez odwołania. W twoim fragmencie kodu znajduje się odwołanie, które jest najpierw przypisane do „Witaj” (automatycznie utworzony obiekt lub pobrany ze stałej puli ), a następnie przypisałeś inny obiekt „Pomoc!” do tego samego odniesienia. Należy zauważyć, że odniesienie jest takie samo i zmodyfikowane, ale obiekty są różne. Jeszcze jedną rzecz w twoim kodzie uzyskałeś dostęp do trzech obiektów,
Wywołanie new String () tworzy nowy obiekt, nawet jeśli istnieje on w puli łańcuchów, więc na ogół nie należy go używać. Aby umieścić ciąg utworzony z nowej funkcji String () w puli ciągów, możesz wypróbować tę
intern()
metodę.Mam nadzieję, że to pomoże.
źródło
Niezmienność mogę powiedzieć, że nie można zmienić samego łańcucha. Załóżmy, że masz ciąg x, którego wartość to „abc”. Teraz nie możesz zmienić łańcucha, to znaczy nie możesz zmienić żadnego znaku / znaków w „abc”.
Jeśli musisz zmienić dowolny znak / ciągi, możesz użyć tablicy znaków i zmutować ją lub użyć StringBuilder.
Wynik:
źródło
Lub możesz spróbować:
To pokaże, jak zmienia się kod skrótu.
źródło
Ciąg jest niezmienny, oznacza to, że nie można zmienić samego obiektu, ale można zmienić odwołanie do obiektu. Kiedy wywołałeś a = „ty”, tak naprawdę zmieniasz odniesienie a na nowy obiekt utworzony przez dosłowny ciąg „ty”. Zmiana obiektu oznacza użycie jego metod do zmiany jednego z jego pól (lub pola są publiczne i nie są ostateczne, dzięki czemu można je aktualizować z zewnątrz bez dostępu do nich metodami), na przykład:
Będąc w niezmiennej klasie (zadeklarowanej jako końcowa, aby zapobiec modyfikacji przez dziedziczenie) (jej metody nie mogą modyfikować swoich pól, a także pola są zawsze prywatne i zaleca się, aby były ostateczne), na przykład Ciąg, nie można zmienić bieżącego Ciąg, ale użytkownik może zwrócić nowy ciąg znaków, tzn .:
źródło
W tym przypadku niezmienność oznacza, że instancja może wskazywać na inne odwołanie, ale oryginalna treść ciągu nie zostanie zmodyfikowana w pierwotnym odwołaniu. Pozwól, że wyjaśnię pierwszy podany przez ciebie przykład. Pierwszy ciąg wskazuje na „Hello”, jest OK do tego. Drugi raz wskazuje na „Pomoc!”. Tutaj zaczął wskazywać „Pomoc!” odwołanie do ciągu „Hello” zostało utracone i nie możemy go odzyskać.
W rzeczywistości, gdy str spróbuje zmodyfikować istniejącą zawartość, wówczas zostanie wygenerowany kolejny nowy ciąg i str zacznie wskazywać na to odwołanie. Widzimy więc, że ciąg w oryginalnym odwołaniu nie jest modyfikowany, ale jest bezpieczny w swoim odwołaniu, a instancja obiektu zaczęła wskazywać na inne odwołanie, więc niezmienność jest zachowana.
źródło
Bardzo późno na odpowiedź, ale chciałem przekazać zwięzłą wiadomość od autora klasy String w Javie
Z tej dokumentacji można wywnioskować, że wszystko, co zmienia ciąg, zwraca inny obiekt (który może być nowy lub internowany i stary). Nie tak subtelna wskazówka na ten temat powinna pochodzić z podpisu funkcji. Pomyśl o tym: „Dlaczego sprawili, że funkcja na obiekcie zwróciła obiekt zamiast statusu?”.
Również jeszcze jedno źródło, które wyraźnie wyjaśnia to zachowanie (z dokumentacji funkcji zastępowania)
Źródło: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char)
Źródło: JavaDoc of String.
źródło
Łańcuch obiektowy - same metody są „niezmienne”. Ta akcja nie powoduje żadnych zmian: „letters.replace („ bbb ”,„ aaa ”);”
Ale przypisanie danych powoduje zmiany w treści Strings:
// Kod skrótu ciągu Obiekt nie zmienia się.
źródło
Jeśli
HELLO
jest to Twój Ciąg, nie możesz zmienićHELLO
naHILLO
. Ta właściwość nosi nazwę właściwości niezmienności.Możesz mieć wiele zmiennych typu String wskaźnika, aby wskazywać łańcuch HELLO.
Ale jeśli HELLO jest char Array, możesz zmienić HELLO na HILLO. Na przykład,
Języki programowania mają niezmienne zmienne danych, dzięki czemu można ich używać jako kluczy w parze klucz-wartość.
źródło
Wyjaśniłbym to prostym przykładem
na tablicy znaków możemy wykonywać operacje takie jak drukowanie tylko trzech ostatnich liter przy użyciu iteracji tablicy; ale w ciągu musimy utworzyć nowy obiekt String i skopiować wymagany podciąg, a jego adres będzie w nowym obiekcie string.
na przykład
więc s2 będzie miał „hel”;
źródło
Łańcuch w Javie w Immutable i Final oznacza po prostu, że nie można go zmienić ani zmodyfikować:
Przypadek 1:
Przypadek 2:
źródło
Ponieważ String jest niezmienny, więc zmiany nie wystąpią, jeśli nie przypiszesz zwróconej wartości funkcji do string. Więc w swoim pytaniu przypisz wartość funkcji swap zwróconej do s.
s = zamiana (s, n1, n2); wówczas zmieni się wartość ciągu s.
Otrzymywałem również niezmienioną wartość, gdy pisałem program, aby uzyskać ciąg permutacji (chociaż nie daje wszystkich permutacji, ale jest to na przykład odpowiedź na twoje pytanie)
Oto przykład.
ale nie otrzymywałem permutowanych wartości ciągu z powyższego kodu. Więc przypisałem zwróconą wartość funkcji zamiany do ciągu i otrzymałem zmienione wartości ciągu. po przypisaniu zwróconej wartości otrzymałem permutowane wartości ciągu.
źródło
Będzie produkować umieścić coś takiego
1419358369 1419358369
103056 65078777
Celem niezmiennego obiektu jest to, że jego wartość nie powinna być zmieniana po przypisaniu. Zwróci nowy obiekt za każdym razem, gdy spróbujesz go zmienić w oparciu o implementację. Uwaga: Aby uniknąć tego, można użyć bufora łańcuchowego zamiast łańcucha.
Na twoje ostatnie pytanie: będziesz miał jedno odwołanie i 2 ciągi w puli ciągów. Z wyjątkiem tego, że odniesienie wskaże na m! Ss! Ss! Pp!
źródło