为什么这不是抛出一个NullPointerException?
需要澄清以下代码:
StringBuilder sample = new StringBuilder(); StringBuilder referToSample = sample; referToSample.append("B"); System.out.println(sample);
这将打印B
以便certificatesample
和referToSample
对象引用相同的内存引用。
StringBuilder sample = new StringBuilder(); StringBuilder referToSample = sample; sample.append("A"); referToSample.append("B"); System.out.println(referToSample);
这将打印AB
也certificate相同。
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,那么sample也应该是null,它应该抛出一个NullPointerException,但它不会抛出一个,为什么?
null
分配不会通过全局销毁该对象来更改值 。 这种行为会导致难以跟踪的错误和违反直觉的行为。 他们只是打破了具体的参考 。
为了简单起见,我们假设sample
指向地址12345.这可能不是地址,只是用于使事情变得简单。 该地址通常用 1 Object#hashCode()
给出的奇怪的hex表示,但是这取决于实现。
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
”的线条See diagram
,当时的对象图如下:
图1:
[StringBuilder sample] -----------------> [java.lang.StringBuilder@00012345] ↑ [StringBuilder referToSample] ------------------------/
图2:
[StringBuilder sample] -----------------> [java.lang.StringBuilder@00012345] [StringBuilder referToSample] ---->> [null pointer]
图2显示了取消引用sample
不会将sample
的引用中断到StringBuilder在00012345
。
1 GC的考虑使得这个不合理。
最初,正如你所说的,参考sample
是指如下所示的sample
:
1.情景1:
2.情景1(续):
-
在这里作为参考
sample
是指sample
,所以它附加“B”,而你写referToSample.append("B")
情景2中发生同样的事情:
但是,情况3:如六分法所说,
当你指定null
指向referToSample
时候,它并没有改变数值,而只是打断了sample
的引用 ,现在它指向没有了 。 如下所示:
现在,当referToSample
指向无处 ,所以当你referToSample.append("A");
它不会有任何值或引用它可以附加A.所以,它会抛出NullPointerException
。
但是sample
与您初始化的sample
相同
StringBuilder sample = new StringBuilder();
所以它已经被初始化了,所以现在它可以附加A,并且不会抛出NullPointerException
简而言之:您将null分配给引用variables,而不是分配给对象。
在一个示例中,您可以更改由两个引用variables引用的对象的状态 。 发生这种情况时,两个参考variables都会反映这个变化。
在另一个例子中,你改变了分配给一个variables的引用,但是这对对象本身没有影响,所以仍然引用原始对象的第二个variables不会注意到对象状态的任何变化。
至于你的具体“规则”:
如果两个对象引用相同的对象,那么如果我们改变任何值,那么它也将反映到其他的,因为它们都指向相同的内存引用。
再次提到改变两个variables引用的一个对象的状态 。
那么为什么这个规则不适用于这里? 如果我将null指派给referToSample,那么sample也应该是null,它应该抛出nullPointerException,但不是抛出,为什么?
再一次,你改变了一个variables的引用 ,这个variables对另一个variables的引用完全没有影响 。
这是两个完全不同的行动,将导致两个完全不同的结果。
看到这个简单的图表:
当你在referToSample
上调用方法时, [your object]
被更新,所以它也会影响sample
。 但是当你说referToSample = null
,你只需要改变referToSample
引用的东西。
这里的'sample'和'referToSample'是引用同一个对象。也就是不同指针访问同一个内存位置的概念。 因此,将一个引用variables赋值为null不会破坏该对象。
referToSample = null;
意味着只有指向null的“referToSample”,对象保持不变,其他引用variables正常工作。 所以对于没有指向null并且有一个有效对象的'sample'
sample.append("A");
工作正常。 但是,如果我们尝试将null追加到“referToSample”,它将显示NullPointException。 那是,
referToSample .append("A");-------> NullPointerException
这就是为什么你的第三个代码片段中有NullPointerException。
每当使用一个新的关键字时,它在堆上创build一个对象
1)StringBuilder sample = new StringBuilder();
2) StringBuilder referToSample = sample;
在2)referenceSamples是在同一个对象样本上创build的
因此referToSample = null; 是空值只有参考样本参考不会影响样本这就是为什么你没有得到NULL指针exception感谢Java的垃圾收集
简单来说,Java没有引用,它只是通过对象引用。