89

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.

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.

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.

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. 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?

commit
  • 4,777
  • 15
  • 43
  • 70
  • 31
    `sample` is still `sample`. You only changed `referToSample`. – Dave Newton Sep 05 '13 at 12:40
  • 25
    Upvoted/starred! Very basic question, but this is a beautiful example of explaining your problem *and* asking the question well. – Ryan Ransford Sep 05 '13 at 12:47
  • @DaveNewton I am asking the same, this rule should also apply for first two example. – commit Sep 05 '13 at 12:52
  • What rule do you refer to? – Hovercraft Full Of Eels Sep 05 '13 at 12:54
  • @HovercraftFullOfEels now I got clear – commit Sep 05 '13 at 13:02
  • 15
    One point of terminology in your question: you keep referring to `sample` and `referToSample` as **objects** but they aren't objects, they are variables. A variable can hold a reference to an object, but it is not itself an object. It's a subtle distinction, but it's basically the essence of your confusion. – Daniel Pryden Sep 05 '13 at 19:16
  • Wait I think I saw a similar question just a few weeks ago... http://stackoverflow.com/questions/18229463/reference-type-in-c-sharp – Alvin Wong Sep 06 '13 at 08:22
  • 1
    It helps to think of object variables as just pointers. Any operator which acts on a variable (`volatile`, `final`, `=`, `==`...) when applied to an object variable affects the _pointer_, not the object it refers to. – MikeFHay Sep 07 '13 at 20:31
  • @AlvinWong I am not aware of C# and haven't look for the same ever. – commit Sep 07 '13 at 20:53
  • 1
    This is a perfect example of asking a simple question in stupendous manner. When i was reading through it, i thought something big concept is hidden inside but the last example was like :D . – Arpit Sep 11 '13 at 06:57
  • 2
    @Arpit I respectfully disagree. There is a big concept hidden in this question, and that is, the difference between an _object_ and a _reference_ to that object. Most of the time, we don't need (nor want) to be aware of this difference, and language designers work hard to hide it from us. Just think of pass-by-reference arguments in C++, for instance. So it's not surprising to me to see beginners confused by all that magic ! – Gyom Sep 11 '13 at 15:08
  • @Gyom if you prefer a good book then its not difficult to understand this concept. :) – Arpit Sep 11 '13 at 19:13
  • @Arpit There *is* a lesson and a concept here. You may be experienced with Java and consider it trivial, but for somebody entering Java as a first language or especially from something like pure C(or even assembly), this concept may be new and counterintuitive. – nanofarad Sep 14 '13 at 16:36
  • @hexafraction I'm not saying anything about why it is asked. But the question is simple, Now again the thing is which book one is referring. If one is writing that program it means that one is familiar with the object and classes. isn't it? and if one is familiar with objects then i can safely assume that if the book were good then this doubt wouldn't be present. – Arpit Sep 14 '13 at 19:44
  • @Arpit The book will likely leave it out as it's not of great importance for someone that is picking up Java *as a first language*. For someone migrating, they *already* have concepts in their mind, and probably use idioms that would break upon the pass-by-value-of-reference way of passing objects in Java. – nanofarad Sep 14 '13 at 19:45
  • @hexafraction in that case i will say "Choose your book wisely". and if the book is skipping this concept then one should change it immediately. – Arpit Sep 14 '13 at 19:49
  • @Arpit sometimes we get better idea about the thing by asking the peoples who know about it rather going to find it in books, that's why we all are here. – commit Sep 23 '13 at 14:51
  • @commit Now this is something that matches to me. :) – Arpit Sep 23 '13 at 18:02

7 Answers7

89

null assignments do not change value by globally destroying that object. 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. The address is typically represented with the weird hexadecimal given in Object#hashCode(), but this is implementation-dependent.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:

Diagram 1:

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

Diagram 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.

1GC considerations make this implausible.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
nanofarad
  • 40,330
  • 4
  • 86
  • 117
  • @commit, if this answers your question, please click the tick below the vote arrows to the left of the text above. – Ray Britton Sep 05 '13 at 14:56
  • @RayBritton I love how people assume that the highest voted answer is the one that necesarily answers the question. While that count is important it is not the only metric; -1 and -2 answers can get accepted just because they helped the OP the most. – nanofarad Sep 05 '13 at 14:57
  • @hexafraction I thought `null` is a value so if I assign to one it should also assign to other but as simple example given by you I got clear and just for I want to know that if I assign any object with `null` it will refer to `00000` kind of address or is just an example? – commit Sep 05 '13 at 15:38
  • @commit Yes, it will refer to a special address(or one of a set) that means a null value, presumably 000000. The numbers here are examples, however. It just means that it's just referring to nothing in particular. – nanofarad Sep 05 '13 at 15:40
  • @hexafraction I asked commit to mark your answer correct as they said that your answer had answered their question. – Ray Britton Sep 05 '13 at 15:48
  • 11
    `hashCode()` is **not** the same thing as memory address – Kevin Panko Sep 05 '13 at 18:29
  • @KevinPanko Right, Object#hashCode is native and implementation-dependent. Better now? – nanofarad Sep 05 '13 at 18:44
  • 6
    The identity hashCode is typically derived from the Object’s memory location the first time the method is called. From then on that hashCode is fixed and remembered even if the memory manager decides to move the object to a different memory location. – Holger Sep 05 '13 at 20:05
  • 3
    Classes which override `hashCode` typically define it to return a value that has nothing to do with memory addresses. I think you can make your point about object references vs. objects without mentioning `hashCode`. The finer points of how to get the memory address can be left for another day. – Kevin Panko Sep 05 '13 at 20:09
  • @KevinPanko I am not referring to overridden hash codes, namely `Object#hashCode`. Removed, anyway, – nanofarad Sep 05 '13 at 20:18
  • for 2 given objects of the same class; a and b | hashCode(a) == hashCode(b) ~ a.equals(b) but not necessarily a == b – Khaled.K Sep 11 '13 at 03:34
  • @KhaledAKhunaifer Yes, that is correct. I was discussing the special implementation of `identityHashCode` which was used in `Object#hashCode` when no hashcode was specifically provided, but this is really not the place to jump into said intricacies as Kevin Panko mentioned. – nanofarad Sep 11 '13 at 10:28
62

Initially it was as you said referToSample was referring to sample as shown below:

1. Scenario1:

referToSample refers to sample

2. Scenario1 (cont.):

referToSample.append("B")

  • Here as referToSample was referring to sample, so it appended "B" while you write

    referToSample.append("B")

Same thing happend in Scenario2 :

But, in 3. Scenario3 : as hexafraction said,

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. as shown below:

when referToSample = null

Now, as referToSample points nowhere, so while you referToSample.append("A"); it would not be have any values or reference where it can append A. So, it would throw NullPointerException.

BUT sample is still the same as you had initialized it with

StringBuilder sample = new StringBuilder(); so it has been initalized, so now it can append A, and will not throw NullPointerException

Parth Soni
  • 11,158
  • 4
  • 32
  • 54
  • 5
    Nice diagrams. Helps to illustrate it. – nanofarad Sep 06 '13 at 06:55
  • nice diagram, but the note at the bottom should be 'Now referToSample does not refer to ""' because when you do `referToSample = sample;` you are referring to sample, you're just copying the address of what is referenced – Khaled.K Sep 11 '13 at 03:37
17

In a nutshell: You assign null to a reference variable, not to an object.

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?

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.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
8

See this simple diagram:

diagram

When you call a method on referToSample, then [your object] is updated, so it affects sample too. But when you say referToSample = null, then you're simply changing what referToSample refers to.

tckmn
  • 57,719
  • 27
  • 114
  • 156
3

Here 'sample' and 'referToSample' are referencing the same object.That is the concept of different pointer accessing same memory location. So assigning one reference variable to null does not destroy the object.

   referToSample = null;

means 'referToSample' only pointing to null , object remains same and other reference variable are working fine. So for 'sample' which does not pointing to null and have a valid object

   sample.append("A");

works fine. But if we try to append null to 'referToSample', it will show NullPointException. That is,

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

That is why you got NullPointerException in your third code snippet.

nanofarad
  • 40,330
  • 4
  • 86
  • 117
NCA
  • 810
  • 1
  • 8
  • 19
0

Whenever a new keyword is used it Creates a Object at the Heap

1)StringBuilder sample = new StringBuilder();

2)StringBuilder referToSample = sample;

In 2) the Reference of referSample is created on same object sample

thus 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

Nitesh Tiwari
  • 4,742
  • 3
  • 28
  • 46
0

Just easy, Java don't have pass by reference, It just pass object reference.

Peerapat A
  • 420
  • 4
  • 13