Почему это не бросает исключение 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 не имеет доступа по ссылке, он просто передает ссылку на объект.