简体   繁体   English

为什么这不会抛出NullPointerException?

[英]Why is this not throwing a NullPointerException?

Nead clarification for following code: 以下代码的澄清说明:

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

This will print B so that proves sample and referToSample objects refer to the same memory reference. 这将打印B以便证明samplereferToSample对象引用相同的内存引用。

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

This will print AB that also proves the same. 这将打印AB ,也证明相同。

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

Obviously this will throw NullPointerException because I am trying to call append on a null reference. 显然这会抛出NullPointerException因为我试图在null引用上调用append

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

So Here is my question, why is the last code sample not throwing NullPointerException because what I see and understand from first two examples is 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. 所以这是我的问题,为什么最后一个代码示例没有抛出NullPointerException因为我从前两个示例中看到和理解的是,如果两个对象引用同一个对象,那么如果我们更改任何值,那么它也会反映到其他,因为它们都指向相同的内存参考。 So why is that rule not applying here? 那么为什么这条规则不适用于此? If I assign null to referToSample then sample should also be null and it should throw a NullPointerException but it is not throwing one, why? 如果我为referToSample分配null ,那么sample也应该为null,它应该抛出一个NullPointerException,但它不会抛出一个,为什么?

null assignments do not change value by globally destroying that object. null赋值不会通过全局销毁该对象来更改 That kind of behavior would lead to hard-to-track bugs and counterintuitive behavior. 这种行为会导致难以追踪的错误和违反直觉的行为。 They only break that specific reference . 他们只打破那个特定的参考

For simplicity, let's say that sample points to address 12345. This is probably not the address, and is only used to make things simple here. 为简单起见,假设sample指向地址12345.这可能不是地址,仅用于简化此处。 The address is typically represented with the weird hexadecimal given in Object#hashCode() , but this is implementation-dependent. 地址 通常Object#hashCode()给出的奇怪的十六进制表示,但这是依赖于实现的。 1 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);

From the lines marked See diagram the diagrams of the objects at that time are as follows: 从标记为See diagram的行中,当时对象的图表如下:

Diagram 1: 图1:

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

Diagram 2: 图2:

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

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

Diagram 2 shows that annulling referToSample does not break the reference of sample to the StringBuilder at 00012345 . 图2显示取消referToSample不会破坏sample00012345处的StringBuilder的00012345

1 GC considerations make this implausible. 1 GC的考虑因素使这一点难以置信。

Initially it was as you said referToSample was referring to sample as shown below: 最初,它是如你所说referToSample指的是sample ,如下图所示:

1. Scenario1: 1.场景1:

referToSample是指样本

2. Scenario1 (cont.): 2.情景1(续):

referToSample.append( “B”)

  • Here as referToSample was referring to sample , so it appended "B" while you write 这里作为referToSample指的是sample ,所以它在你写的时候附加了“B”

    referToSample.append("B")

Same thing happend in Scenario2 : Scenario2中发生了同样的事情

But, in 3. Scenario3 : as hexafraction said, 但是,在3.场景3中:正如hexafraction所说,

when you assign null to referToSample when it was referring sample it did not change value instead it just breaks the reference from sample , and now it points nowhere . 当你在引用sample时为referToSample指定null时,它没有改变值,而只是从sample中断了引用 ,现在它指向了无处 as shown below: 如下所示:

当referToSample = null时

Now, as referToSample points nowhere , so while you referToSample.append("A"); 现在,由于referToSample无处 ,所以当你referToSample.append("A"); it would not be have any values or reference where it can append A. So, it would throw NullPointerException . 它不会有任何值或引用它可以追加A.所以,它会抛出NullPointerException

BUT sample is still the same as you had initialized it with sample仍然与您初始化sample相同

StringBuilder sample = new StringBuilder(); so it has been initalized, so now it can append A, and will not throw NullPointerException 所以它已被初始化,所以现在它可以附加A,并且不会抛出NullPointerException

In a nutshell: You assign null to a reference variable, not to an object. 简而言之:您将null赋给引用变量,而不是对象。

In one example you change the state of an object that is referred to by two reference variables. 在一个示例中,您可以更改由两个引用变量引用的对象的状态 When this occurs, both reference variables will reflect the change. 发生这种情况时,两个参考变量都将反映变化。

In another example, you change the reference assigned to one variable, but this has no effect on the object itself, and so the second variable, which still refers to the original object, will not notice any change in object state. 在另一个示例中,您更改分配给一个变量的引用,但这对对象本身没有影响,因此仍然引用原始对象的第二个变量将不会注意到对象状态的任何更改。


So as to your specific "rules": 至于你的具体“规则”:

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. 如果两个对象引用同一个对象,那么如果我们更改任何值,那么它也会反映到其他对象,因为它们都指向相同的内存引用。

Again, you refer to changing the state of the one object that both variables refer to. 同样,您指的是更改两个变量引用的一个对象的状态

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? 如果我为referToSample分配null,那么sample也应该为null并且它应该抛出nullPointerException但是它没有抛出,为什么?

Again, you change the reference of one variable which has absolutely no effect on the reference of the other variable. 同样,如果改变了对其他变量的基准绝对不会影响一个变量的引用

These are two completely different actions and will result in two completely different results. 这是两个完全不同的动作,将导致两个完全不同的结果。

See this simple diagram: 看到这个简单的图表:

图

When you call a method on referToSample , then [your object] is updated, so it affects sample too. 当您在referToSample上调用方法时, [your object]会更新,因此它也会影响sample But when you say referToSample = null , then you're simply changing what referToSample refers to. 但是当你说referToSample = null ,你只需要改变referToSample 所指的内容。

Here 'sample' and 'referToSample' are referencing the same object.That is the concept of different pointer accessing same memory location. 这里'sample'和'referToSample'引用同一个对象。这是不同指针访问相同内存位置的概念。 So assigning one reference variable to null does not destroy the object. 因此,将一个引用变量赋值为null不会破坏该对象。

   referToSample = null;

means 'referToSample' only pointing to null , object remains same and other reference variable are working fine. 表示'referToSample'仅指向null,对象保持不变,其他引用变量正常工作。 So for 'sample' which does not pointing to null and have a valid object 因此对于'sample'而言,它不指向null并且具有有效对象

   sample.append("A");

works fine. 工作良好。 But if we try to append null to 'referToSample', it will show NullPointException. 但是如果我们尝试将null附加到'referToSample',它将显示NullPointException。 That is, 那是,

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

That is why you got NullPointerException in your third code snippet. 这就是你在第三个代码片段中得到NullPointerException的原因。

Whenever a new keyword is used it Creates a Object at the Heap 每当使用关键字时,它都会在堆中创建一个对象

1)StringBuilder sample = new StringBuilder(); 1)StringBuilder sample = new StringBuilder();

2) StringBuilder referToSample = sample; 2) StringBuilder referToSample = sample;

In 2) the Reference of referSample is created on same object sample 在2)中,在相同的对象样本上创建了referSample的参考

thus referToSample = null; 因此, referToSample = null; is Nulling Only the referSample Reference giving no effect to sample that's why you are not getting NULL Pointer Exception Thanks to Java's Garbage Collection 是否为Nulling只有referSample Reference对样本没有影响,这就是为什么你没有得到NULL指针异常感谢Java的垃圾收集

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM