为什么这不会引发 NullPointerException?

2022-08-31 11:30:42

以下代码的 Nead 说明:

StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample.append("B");
System.out.println(sample);

这将打印,以便证明和对象引用相同的内存引用。BsamplereferToSample

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);

显然,这将抛出,因为我正在尝试调用空引用。NullPointerExceptionappend

StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
sample.append("A");
System.out.println(sample);

所以这是我的问题,为什么最后一个代码示例没有抛出,因为我从前两个例子中看到和理解的是,如果两个对象引用同一个对象,那么如果我们改变任何值,那么它也会反映给其他对象,因为两者都指向相同的内存引用。那么,为什么这条规则在这里不适用呢?如果我分配到 referToSample,那么 sample 也应该是 null,它应该抛出一个 NullPointerException,但它没有抛出一个,为什么?NullPointerExceptionnull


答案 1

null赋值不会通过全局销毁该对象来更改。这种行为会导致难以跟踪的错误和违反直觉的行为。它们只会破坏该特定引用

为简单起见,假设指向地址 12345。这可能不是地址,仅用于使事情变得简单。该地址通常Object#hashCode() 中给出的奇怪的十六进制数表示,但这是依赖于实现的。1 个sample

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);

从标记为“请参阅图”的行中,当时对象的图如下所示:

图1:

[StringBuilder sample]    -----------------> [java.lang.StringBuilder@00012345]
                                                      ↑
[StringBuilder referToSample] ------------------------/

图2:

[StringBuilder sample]    -----------------> [java.lang.StringBuilder@00012345]

[StringBuilder referToSample] ---->> [null pointer]

图 2 显示,取消不会中断 对 StringBuilder 的引用。referToSamplesample00012345

1 个GC的考虑使这难以置信。


答案 2

最初,正如您所说,它指的是如下所示:referToSamplesample

1. 场景1:

referToSample refers to sample

2. 方案1(续):

referToSample.append("B")

  • 这里指的是 ,所以它在你写的时候附加了“B”referToSamplesample

    referToSample.append("B")

同样的事情也发生在场景2中:

但是,在3中。场景3:正如六分法所说,

当你分配到它被引用时,它没有改变,相反,它只是从 中中断引用,现在它无处可去。如下图所示:nullreferToSamplesamplesample

when referToSample = null

现在,作为无处可去的点,所以当你没有任何值或参考可以附加A时。因此,它会抛出.referToSamplereferToSample.append("A");NullPointerException

但仍然与您初始化它时相同sample

StringBuilder sample = new StringBuilder();所以它已经初始化了,所以现在它可以附加A,并且不会扔NullPointerException