为什么这不会抛出NullPointerException?

时间:2013-09-05 12:38:21

标签: java reference nullpointerexception

以下代码的澄清:

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

这将打印B,以便证明samplereferToSample个对象引用相同的内存引用。

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,那么样本也应该为null并且它应该抛出一个NullPointerException,但它不会抛出一个,为什么?

7 个答案:

答案 0 :(得分:89)

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]    -----------------> [java.lang.StringBuilder@00012345]
                                                      ↑
[StringBuilder referToSample] ------------------------/

图2:

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

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

图2显示,取消referToSample并不会将sample的引用中断为00012345处的StringBuilder。

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

答案 1 :(得分:62)

最初正如您所说referToSample指的是sample,如下所示:

<强> 1。 Scenario1:

referToSample refers to sample

<强> 2。场景1(续):

referToSample.append("B")

  • 此处referToSample指的是sample,因此附加了“B” 在你写的时候

    referToSample.append("B")

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

但是,在 3中。场景3: 正如hexafraction所说,

当您将null分配给referToSample时,它引用sample它没有改变而只是打破了引用 >来自sample,现在它指向无处。如下图所示:

when referToSample = null

现在,由于referToSample指向无处,所以当你referToSample.append("A");时,它不会有任何值或引用它可以追加A.所以,它会抛出{ {1}}。

但是NullPointerException仍然与您使用

初始化它相同

sample所以它已被初始化,所以现在它可以追加A,而不会抛出StringBuilder sample = new StringBuilder();

答案 2 :(得分:17)

简而言之:您将null赋给引用变量,而不是对象。

在一个示例中,您可以更改由两个引用变量引用的对象的状态。发生这种情况时,两个参考变量都会反映出变化。

在另一个示例中,您更改分配给一个变量的引用,但这对对象本身没有影响,因此仍然引用原始对象的第二个变量将不会注意到对象状态的任何更改。 / p>


至于你的具体“规则”:

  

如果两个对象引用同一个对象,那么如果我们更改任何值,那么它也会反映给其他,因为它们都指向相同的内存引用。

同样,您指的是更改变量引用的一个对象的状态

  

那么为什么这条规则不适用于此?如果我为referToSample分配null,那么sample也应该为null并且它应该抛出nullPointerException但它不抛出,为什么?

同样,您更改了另一个变量的引用上绝对无效的变量的引用

这是两个完全不同的行为,会导致两个完全不同的结果。

答案 3 :(得分:8)

见这个简单的图表:

diagram

当您在referToSample上调用方法时,[your object]会更新,因此它也会影响sample。但是,当您说referToSample = null时,您只是将referToSample 引用的内容更改为。

答案 4 :(得分:3)

这里'sample'和'referToSample'引用同一个对象。这是不同指针访问相同内存位置的概念。因此,将一个引用变量赋值为null不会破坏该对象。

   referToSample = null;

表示'referToSample'仅指向null,对象保持不变,其他引用变量正常工作。因此,'sample'不指向null并且具有有效对象

   sample.append("A");

工作正常。但是如果我们尝试将null附加到'referToSample',它将显示NullPointException。 也就是说,

   referToSample .append("A");-------> NullPointerException

这就是你在第三个代码片段中得到NullPointerException的原因。

答案 5 :(得分:0)

每当使用 new 关键字时,它会在堆中创建一个对象

1)StringBuilder sample = new StringBuilder();

2) StringBuilder referToSample = sample;

在2)中,在相同的对象样本

上创建了referSample的引用

因此 referToSample = null; Nulling只有referSample Reference对样本没有影响 这就是为什么你没有得到NULL指针异常 感谢Java的垃圾收集

答案 6 :(得分:0)

很简单,Java没有通过引用传递,它只是传递对象引用。