Nead wyjaśnienie dla następującego kodu:
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample.append("B");
System.out.println(sample);
To zostanie wydrukowane w B
taki sposób, że dowody sample
i referToSample
obiekty odnoszą się do tego samego odniesienia do pamięci.
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
sample.append("A");
referToSample.append("B");
System.out.println(referToSample);
Spowoduje to wydrukowanie, AB
które również dowodzi tego samego.
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
referToSample.append("A");
System.out.println(sample);
Oczywiście to się wyrzuci, NullPointerException
ponieważ próbuję wywołać append
odwołanie zerowe.
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
sample.append("A");
System.out.println(sample);
Więc oto moje pytanie, dlaczego ostatni przykład kodu nie jest rzucany, NullPointerException
ponieważ to, co widzę i rozumiem z pierwszych dwóch przykładów, to jeśli dwa obiekty odnoszą się do tego samego obiektu, to jeśli zmienimy jakąkolwiek wartość, to również odbije się to na innej, ponieważ oba wskazują to samo odniesienie do pamięci. Dlaczego więc ta zasada nie ma tutaj zastosowania? Jeśli przypiszę null
do referToSample, sample również powinno mieć wartość null i powinno zgłaszać wyjątek NullPointerException, ale go nie zgłasza, dlaczego?
źródło
sample
jest nadalsample
. Tylko się zmieniłeśreferToSample
.sample
ireferToSample
jako obiekty, ale nie są one obiektami, są zmiennymi. Zmienna może zawierać odniesienie do obiektu, ale sama nie jest obiektem. To subtelne rozróżnienie, ale w zasadzie jest to esencja twojego pomieszania.volatile
,final
,=
,==
...), gdy stosuje się do zmiennej obiektu wpływa na wskaźnik , a nie odnosi się do obiektu.Odpowiedzi:
null
przypisania nie zmieniają wartości poprzez globalne niszczenie tego obiektu. Takie zachowanie prowadziłoby do trudnych do śledzenia błędów i sprzecznych z intuicją zachowań. Łamią tylko to konkretne odniesienie .Dla uproszczenia powiedzmy, że
sample
wskazuje na adres 12345. Prawdopodobnie nie jest to adres i jest używany tylko dla uproszczenia.Adres jest zwykle reprezentowany za pomocą dziwnego szesnastkowego podanego w1Object#hashCode()
, ale jest to zależne od implementacji.StringBuilder sample = new StringBuilder(); //sample refers to //StringBuilder at 12345 StringBuilder referToSample = sample; //referToSample refers to //the same StringBuilder at 12345 //SEE DIAGRAM 1 referToSample = null; //referToSample NOW refers to 00000, //so accessing it will throw a NPE. //The other reference is not affected. //SEE DIAGRAM 2 sample.append("A"); //sample STILL refers to the same StringBuilder at 12345 System.out.println(sample);
Z zaznaczonych linii
See diagram
schematy obiektów w tym czasie przedstawiają się następująco:Schemat 1:
[StringBuilder sample] -----------------> [java.lang.StringBuilder@00012345] ↑ [StringBuilder referToSample] ------------------------/
Schemat 2:
[StringBuilder sample] -----------------> [java.lang.StringBuilder@00012345] [StringBuilder referToSample] ---->> [null pointer]
Diagram 2 pokazuje, że anulowanie
referToSample
nie przerywa odwołaniasample
do StringBuilder w00012345
.1 Rozważania GC sprawiają, że jest to nieprawdopodobne.
źródło
hashCode()
to nie to samo, co adres pamięcihashCode
zazwyczaj definiują ją jako zwracającą wartość, która nie ma nic wspólnego z adresami pamięci. Myślę, że bez wspominania o tym można poruszyć kwestię odniesień do obiektów i obiektówhashCode
. Dokładniejsze informacje, jak uzyskać adres pamięci, można zostawić na inny dzień.Początkowo była jak mówiłeś
referToSample
miał na myślisample
, jak pokazano poniżej:1. Scenariusz 1:
2. Scenariusz 1 (ciąg dalszy):
Tutaj jak się
referToSample
odnosiłeśsample
, więc podczas pisania zostało dodane „B”referToSample.append("B")
To samo stało się w Scenariuszu 2:
Ale w 3. Scenariuszu 3: jak powiedział hexafraction,
po przypisaniu
null
doreferToSample
kiedy odnosiłsample
się nie zmienił wartości , zamiast po prostu łamie odwołanie odsample
, a teraz wskazuje nigdzie . jak pokazano niżej:Teraz, ponieważ nigdzie nie
referToSample
wskazuje , więc podczas gdy ty nie miałbyś żadnych wartości ani odniesień, w których może dołączyć A. Więc to rzuci .referToSample.append("A");
NullPointerException
ALE
sample
jest nadal taki sam, jak zainicjowałeś goStringBuilder sample = new StringBuilder();
więc został zainicjalizowany, więc teraz może dołączyć A i nie będzie rzucałNullPointerException
źródło
referToSample = sample;
się do próbki, po prostu kopiujesz adres tego, do czego się odnosiW skrócie: przypisujesz wartość null zmiennej referencyjnej, a nie obiektowi.
W jednym przykładzie zmieniasz stan obiektu, do którego odwołują się dwie zmienne odniesienia. W takim przypadku obie zmienne odniesienia będą odzwierciedlać zmianę.
W innym przykładzie zmieniasz odniesienie przypisane do jednej zmiennej, ale nie ma to wpływu na sam obiekt, więc druga zmienna, która nadal odwołuje się do oryginalnego obiektu, nie zauważy żadnej zmiany stanu obiektu.
Jeśli chodzi o Twoje szczegółowe „zasady”:
Ponownie odnosisz się do zmiany stanu jednego obiektu, do którego odnoszą się obie zmienne .
Ponownie, zmieniasz referencję jednej zmiennej, która nie ma absolutnie żadnego wpływu na referencję drugiej zmiennej.
Są to dwie zupełnie różne czynności i skutkują dwoma zupełnie różnymi rezultatami.
źródło
Zobacz ten prosty diagram:
Kiedy można nazwać metodę na
referToSample
, a następnie[your object]
jest aktualizowany, dzięki czemu wpływasample
też. Ale kiedy mówiszreferToSample = null
, po prostu zmieniasz to, do czego sięreferToSample
odnosi .źródło
Tutaj „sample” i „referToSample” odnoszą się do tego samego obiektu. To jest koncepcja różnych wskaźników uzyskujących dostęp do tego samego miejsca w pamięci. Zatem przypisanie jednej zmiennej referencyjnej do wartości null nie niszczy obiektu.
referToSample = null;
oznacza, że „referToSample” wskazuje tylko na wartość null, obiekt pozostaje taki sam, a inne zmienne odniesienia działają dobrze. Tak więc dla „próbki”, która nie wskazuje na wartość null i ma prawidłowy obiekt
sample.append("A");
działa w porządku. Ale jeśli spróbujemy dodać null do 'referToSample', wyświetli się NullPointException. To jest,
referToSample .append("A");-------> NullPointerException
Dlatego w trzecim fragmencie kodu masz wyjątek NullPointerException.
źródło
Za każdym razem, gdy używane jest nowe słowo kluczowe, tworzy ono obiekt na stercie
1) StringBuilder sample = new StringBuilder ();
2) StringBuilder referToSample = sample;
W 2) referencja referSample jest tworzona na tej samej próbce obiektu
zatem referToSample = null; ma wartość Nulling Tylko odwołanie referSample nie daje żadnego wpływu na sample dlatego nie otrzymujesz wyjątku wskaźnika NULL Dzięki funkcji Garbage Collection w Javie
źródło
Po prostu proste, Java nie ma przekazywania przez referencję, po prostu przekazuje referencję do obiektu.
źródło