Почему это не бросает исключение NullPointerException?
Прояснение Nead для следующего кода:
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample.append("B");
System.out.println(sample);
Это напечатает B
, чтобы доказать, что объекты sample
и referToSample
относятся к одной и той же ссылке на память.
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
sample.append("A");
referToSample.append("B");
System.out.println(referToSample);
Это будет печатать AB
, что также доказывает то же самое.
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
referToSample.append("A");
System.out.println(sample);
Очевидно, что это вызовет NullPointerException
, потому что я пытаюсь вызвать append
по нулевой ссылке.
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
sample.append("A");
System.out.println(sample);
Итак, вот мой вопрос: почему последний пример кода не бросает NullPointerException
, потому что то, что я вижу и понимаю из первых двух примеров, - это если два объекта ссылаются на один и тот же объект, то, если мы изменим какое-либо значение, то оно также будет отражать другое, потому что оба указывают на одну и ту же память. Так почему же это правило не применяется здесь? Если я назначу null
на referToSample, тогда образец также должен быть пустым, и он должен вызывать исключение NullPointerException, но он не выбрасывает его, почему?
Ответы
Ответ 1
null
присваивания не изменяют значение, глобально уничтожая этот объект. Такое поведение приведет к труднодоступным ошибкам и противоречивому поведению. Они только нарушают эту конкретную ссылку.
Для простоты скажем, что sample
указывает на адрес 12345. Это, вероятно, не адрес, а используется только для упрощения. Адрес обычно представлен странным шестнадцатеричным значением, указанным в Object#hashCode()
, но это зависит от реализации. 1
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);
От строк, отмеченных See diagram
, диаграммы объектов в это время выглядят следующим образом:
Диаграмма 1:
[StringBuilder sample] -----------------> [[email protected]]
↑
[StringBuilder referToSample] ------------------------/
Диаграмма 2:
[StringBuilder sample] -----------------> [[email protected]]
[StringBuilder referToSample] ---->> [null pointer]
Диаграмма 2 показывает, что аннулирование referToSample
не нарушает ссылку sample
на StringBuilder в 00012345
.
1 соображения GC делают это неправдоподобным.
Ответ 2
Изначально это было так, как вы сказали referToSample
имел в виду sample
, как показано ниже:
1. Scenario1:
![referToSample refers to sample]()
2. Сценарий1 (продолжение):
![referToSample.append("B")]()
-
Здесь, как referToSample
имел в виду sample
, поэтому он добавил "B"
в то время как вы пишете
referToSample.append("B")
То же самое произошло в Сценарии2:
Но в 3. Сценарий 3:, как указано в гексафракции,
когда вы присваиваете null
до referToSample
, когда он ссылался на sample
, он не менял значение, а просто разбивал ссылку на sample
, и теперь это нигде не упоминается. как показано ниже:
![when referToSample = null]()
Теперь, поскольку referToSample
не указывает нигде, поэтому, пока вы referToSample.append("A");
, у него не будет никаких значений или ссылок, где он может добавить A. Таким образом, он выбрал бы NullPointerException
.
НО sample
по-прежнему совпадает с инициализацией
StringBuilder sample = new StringBuilder();
, поэтому он был инициализирован, поэтому теперь он может добавить A и не будет бросать NullPointerException
Ответ 3
В двух словах: вы присваиваете значение null ссылочной переменной, а не объекту.
В одном примере вы изменяете состояние объекта, на который ссылаются две контрольные переменные. Когда это произойдет, обе ссылочные переменные будут отражать изменение.
В другом примере вы изменяете ссылку, назначенную одной переменной, но это не влияет на сам объект, поэтому вторая переменная, которая все еще относится к исходному объекту, не заметит изменений в состоянии объекта.
Что касается ваших конкретных "правил":
если два объекта ссылаются на один и тот же объект, тогда, если мы изменим любое значение, оно также будет отражено в другом, поскольку оба указывают на одну и ту же ссылку на память.
Опять же, вы ссылаетесь на изменение состояния одного объекта, к которому относятся обе переменные.
Так почему же это правило не применяется здесь? Если я назначаю null для referToSample, тогда образец также должен быть нулевым, и он должен вызывать исключение nullPointerException, но он не бросает, почему?
Опять же, вы меняете ссылку на одну переменную, которая абсолютно не влияет на ссылку другой переменной.
Это два совершенно разных действия и приведет к двум совершенно другим результатам.
Ответ 4
См. эту простую диаграмму:
![diagram]()
Когда вы вызываете метод на referToSample
, обновляется [your object]
, поэтому он также влияет на sample
. Но когда вы говорите referToSample = null
, вы просто меняете то, что referToSample
ссылается на.
Ответ 5
Здесь "sample" и "referToSample" ссылаются на один и тот же объект. Это понятие о том, что другой указатель обращается к тому же месту памяти. Поэтому назначение одной ссылочной переменной в значение null не уничтожает объект.
referToSample = null;
означает, что 'referToSample' указывает только на null, объект остается таким же, а другая ссылочная переменная работает нормально. Итак, для 'sample', который не указывает на null и имеет действительный объект
sample.append("A");
работает отлично. Но если мы попытаемся добавить значение null в 'referToSample', оно отобразит исключение NullPointException.
То есть
referToSample .append("A");-------> NullPointerException
Вот почему вы получили NullPointerException в своем третьем фрагменте кода.
Ответ 6
Всякий раз, когда используется ключевое слово новое, оно создает объект в куче
1) StringBuilder sample = new StringBuilder();
2) StringBuilder referToSample = sample;
В 2) Ссылка на ссылочный образец создается на одном и том же объекте
таким образом referToSample = null;
Nulling Только ссылка ReferSample Reference, не влияющая на выборку
почему вы не получаете исключение NULL Pointer Exception
Благодаря сборке мусора Java
Ответ 7
Просто, Java не имеет доступа по ссылке, он просто передает ссылку на объект.