Assigning one primitive variable to another vs a reference variable to another

David picture David · Jul 8, 2015 · Viewed 7.6k times · Source

I would like to understand how primitive and object reference variable behaves differently. I have used the below code from OCA/OCP Java SE7 by Kathy Sierra as an example:

public class VariableTesting {
    public static void main(String[] args) {
        int a = 10;
        System.out.println("a= " + a);

        int b = a;
        b = 30;
        System.out.println("a= " + a + " after change it to b and b is " + b);

        Dimension a1 = new Dimension(5, 10);
        System.out.println("a1.height = " + a1.height);

        Dimension b1 = a1;
        b1.height = 30;

        System.out.println("a1.height= " + a1.height + " after change to b1");
    }
}

In the above piece of code, I'm getting the value of a = 10; before and after changing the value of b.

The output for the primitive variable case is:

a = 10
a = 10 after change it to b and b is 30

However, in object reference variable I'm getting a different value once I change the value of b1.height = 30;

The output for the reference variable case is:

a1.height = 10
a1.height = 30 after change to b1

It is mentioned in the book that in both case the bit pattern is copied and a new copy is placed. If this is true, then why we are getting different behavior?

Answer

Makoto picture Makoto · Jul 8, 2015

This is the underpinning difference between a reference and a primitive. In both cases, you're getting the actual value, but only in the case of an object do you have a chance to impact the result of any other usages of it.

Let's walk through the code.

int a = 10;
int b = a;

These two declarations are saying the following:

  • Assign the value 10 to an int identifier called a.
  • Assign the value of a to an int identifier called b.

So far, so good. Nowhere do we say that a is referenced by b; we're only taking values.

If we declare:

b = 30;

We're saying take the value of 30 and assign it to the identifier b.

We don't do anything with a at that point; it already contains the value 10. This is why a and b are different.

Now, when we get to the object, things don't really change on the surface...

Dimension a1 = new Dimension(5, 10);
Dimension b1 = a1;

We translate this as:

  • Assign the value of instantiation of a new Dimension with (int) parameters 5 and 10 to a Dimension identifier a1.
  • Assign the value of a1 to a Dimension identifier b1.

We're still assigning values here, since Java is pass-by-value. The kicker here is that in Java, the value of an object is still a reference to that object.

By the above example, a1 and b1 are pointing to the same instance.

Now, when we state this:

b1.height = 30;

We're actually saying:

  • Assign the value 30 to the field height dereferenced through the value b1.

We're still referring to the value of b1 here, which is tied to a1. This is why you see the difference; because a1 and b1 refer to the same value (which is the same reference), any change done through the identifier b1 is reflected through a1.