[英]Why is this not throwing a NullPointerException?
以下代码的澄清说明:
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
因为我试图在null引用上调用append
。
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
sample.append("A");
System.out.println(sample);
所以这是我的问题,为什么最后一个代码示例没有抛出NullPointerException
因为我从前两个示例中看到和理解的是,如果两个对象引用同一个对象,那么如果我们更改任何值,那么它也会反映到其他,因为它们都指向相同的内存参考。 那么为什么这条规则不适用于此? 如果我为referToSample分配null
,那么sample也应该为null,它应该抛出一个NullPointerException,但它不会抛出一个,为什么?
null
赋值不会通过全局销毁该对象来更改值 。 这种行为会导致难以追踪的错误和违反直觉的行为。 他们只打破那个特定的参考 。
为简单起见,假设sample
指向地址12345.这可能不是地址,仅用于简化此处。
地址
通常用
1 Object#hashCode()
给出的奇怪的十六进制表示,但这是依赖于实现的。
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] -----------------> [java.lang.StringBuilder@00012345]
↑
[StringBuilder referToSample] ------------------------/
图2:
[StringBuilder sample] -----------------> [java.lang.StringBuilder@00012345]
[StringBuilder referToSample] ---->> [null pointer]
图2显示取消referToSample
不会破坏sample
对00012345
处的StringBuilder的00012345
。
1 GC的考虑因素使这一点难以置信。
最初,它是如你所说referToSample
指的是sample
,如下图所示:
1.场景1:
2.情景1(续):
这里作为referToSample
指的是sample
,所以它在你写的时候附加了“B”
referToSample.append("B")
Scenario2中发生了同样的事情:
但是,在3.场景3中:正如hexafraction所说,
当你在引用sample
时为referToSample
指定null
时,它没有改变值,而只是从sample
中断了引用 ,现在它指向了无处 。 如下所示:
现在,由于referToSample
点无处 ,所以当你referToSample.append("A");
它不会有任何值或引用它可以追加A.所以,它会抛出NullPointerException
。
但sample
仍然与您初始化sample
相同
StringBuilder sample = new StringBuilder();
所以它已被初始化,所以现在它可以附加A,并且不会抛出NullPointerException
简而言之:您将null赋给引用变量,而不是对象。
在一个示例中,您可以更改由两个引用变量引用的对象的状态 。 发生这种情况时,两个参考变量都将反映变化。
在另一个示例中,您更改分配给一个变量的引用,但这对对象本身没有影响,因此仍然引用原始对象的第二个变量将不会注意到对象状态的任何更改。
至于你的具体“规则”:
如果两个对象引用同一个对象,那么如果我们更改任何值,那么它也会反映到其他对象,因为它们都指向相同的内存引用。
同样,您指的是更改两个变量引用的一个对象的状态 。
那么为什么这条规则不适用于此? 如果我为referToSample分配null,那么sample也应该为null并且它应该抛出nullPointerException但是它没有抛出,为什么?
同样,如果改变了对其他变量的基准绝对不会影响一个变量的引用 。
这是两个完全不同的动作,将导致两个完全不同的结果。
看到这个简单的图表:
当您在referToSample
上调用方法时, [your object]
会更新,因此它也会影响sample
。 但是当你说referToSample = null
,你只需要改变referToSample
所指的内容。
这里'sample'和'referToSample'引用同一个对象。这是不同指针访问相同内存位置的概念。 因此,将一个引用变量赋值为null不会破坏该对象。
referToSample = null;
表示'referToSample'仅指向null,对象保持不变,其他引用变量正常工作。 因此对于'sample'而言,它不指向null并且具有有效对象
sample.append("A");
工作良好。 但是如果我们尝试将null附加到'referToSample',它将显示NullPointException。 那是,
referToSample .append("A");-------> NullPointerException
这就是你在第三个代码片段中得到NullPointerException的原因。
每当使用新关键字时,它都会在堆中创建一个对象
1)StringBuilder sample = new StringBuilder();
2) StringBuilder referToSample = sample;
在2)中,在相同的对象样本上创建了referSample的参考
因此, referToSample = null; 是否为Nulling只有referSample Reference对样本没有影响,这就是为什么你没有得到NULL指针异常感谢Java的垃圾收集
只是简单,Java没有通过引用传递,它只是传递对象引用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.