关于java:为什么这不会抛出NullPointerException?

Why is this not throwing a NullPointerException?

NEAD对以下代码的澄清:

1
2
3
4
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample.append("B");
System.out.println(sample);

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

1
2
3
4
5
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
sample.append("A");
referToSample.append("B");
System.out.println(referToSample);

这将打印也证明相同的AB

1
2
3
4
5
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
referToSample.append("A");
System.out.println(sample);

显然,这将抛出NullPointerException,因为我正试图在空引用上调用append

1
2
3
4
5
StringBuilder sample = new StringBuilder();
StringBuilder referToSample = sample;
referToSample = null;
sample.append("A");
System.out.println(sample);

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


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

为了简单起见,我们假设sample指向地址12345。这可能不是地址,只是用来简化这里的事情。地址通常用Object#hashCode()中给出的奇怪的十六进制表示,但这取决于实现。1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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:

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

图2:

1
2
3
[StringBuilder sample]    -----------------> [java.lang.StringBuilder@00012345]

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

图2表明,取消referToSample不会破坏sample00012345处架线工的参考。

1gc考虑因素使这不可信。


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

1。情景1:

referToSample refers to sample

2。场景1(续):

referToSample.append(

  • 这里,因为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();所以已经初始化了,所以现在可以附加一个,不会抛出NullPointerException


简而言之:您将空值赋给一个引用变量,而不是一个对象。

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

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

至于你的具体"规则":

if two objects referring to same object then if we change any value then it will also reflect to other because both are pointing to same memory reference.

同样,您也提到更改两个变量所引用的一个对象的状态。

So why is that rule not applying here? If I assign null to referToSample then sample should also be null and it should throw nullPointerException but it is not throwing, why?

同样,更改一个变量的引用,这对另一个变量的引用绝对没有影响。

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


见下图:

diagram

当您在referToSample上调用一个方法时,[your object]会被更新,因此它也会影响sample。但是当你说referToSample = null时,你只是在改变referToSample所指的。


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

1
   referToSample = null;

表示"referToSample"只指向空值,对象保持不变,其他引用变量工作正常。所以对于不指向空并且具有有效对象的"sample"

1
   sample.append("A");

工作良好。但如果我们尝试将空值附加到"referToSample",它将显示nullpointException。也就是说,

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

这就是为什么在第三个代码片段中出现nullpointerException。


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


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

1)StringBuilder示例=new StringBuilder();

2)StringBuilder referToSample=示例;

在2)referesample的引用是在同一对象样本上创建的。

因此referToSample=空;仅使引用的样本引用无效这就是为什么您没有得到空指针异常的原因。感谢Java的垃圾回收