-1

I'm not sure if I understand how pass-by-value works in Java. I know there are many topics about that, even on SO, but they all don't really fit and I'd like to know if I'm right:

Lets say I've got the following Code:

class Class{
    public String className;
    public Person p;
}

class Person {
    public String name;
}

The thing I don't 100% understand is:

Class c = new Class(); // reference of the object oC is stored in var c
Person p = new Person();// reference of the object oP is stored in var p
p.name = "StudName"; // value = reference of string s is stored in var p
c.p = p; // reference of p is updated to point to oP
p = new Person(); // Confusing Part (1)

So as far as I understand, each Variable has a given space in the Stack and points to the reference of the object right? So am I correct, that the p = new Person(); doesn't affect the reference in the c Object, because this operation sets the reference of p to the one from the newly created Person object?

I find that hard to understand, because if I do something like that:

c.p = new Person();//(2)

This will affect the reference of c.p of course. But what's the difference between (1) and (2)?

Chris
  • 1
  • 1
  • probably duplicate https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – Jacek Cz Sep 17 '17 at 15:36
  • @JacekCz No it's not really a duplicate, because there is not explained how the re-assigining works like here – Chris Sep 17 '17 at 15:38
  • Actually "value = reference of string s is stored in var p" is wrong. It is not stored in p, but in the field "name". In (1) you say that the variable p will be a reference to a new Person. In (2) you say that the reference p stored as a variable in c will point to a new Person. In (2), c will still point to the original Class instance. – peterulb Sep 17 '17 at 15:41

3 Answers3

3

Your question has nothing to do with pass-by-value*. Your question is about object references.

each Variable has a given space in the Stack and points to the reference of the object right?

You have one too many levels of indirection in there. :-) The variable contains the object reference.

Think of an object reference as an int that tells the JVM where the object is elsewhere in memory. (That's not literally true, but it's a very good way of thinking about it.)

So in:

c.p = p;

the value in p (an object reference saying where that Person object is) is copied into c.p, modifying the state of the object c. There is no ongoing relationship between p and c.p, they just happen to contain the same value for the moment.

This is exactly like if we had an int i in the class and did:

int i = 42;
c.i = i;

The value in i is copied into c.i, modifying the state of c.

After the c.p = ... line, when you do this:

p = new Person(); // Confusing Part (1)

...it has no effect on c.p at all. It just creates a new Person object and stores the object reference in p. c.p still has the old value (the reference to the earlier object).

But what's the difference between (1) and (2)?

In (1), you're assigning to p, not c.p; doing so has no effect on c.p. In (2) you're assigning to c.p.

Let's follow that first code block through, but I'm going to use Container rather than Class as Java already has a Class class. After you do this:

Container c = new Container();
Person p = new Person();
p.name = "StudName";

you have something like this in memory:

                 +−−−−−−−−−−−−−−−−−+
c: [Ref11325]−−−>|   (Container)   |
                 +−−−−−−−−−−−−−−−−−+
                 | className: null |
                 | p: null         |
                 +−−−−−−−−−−−−−−−−−+

                                         +−−−−−−−−−−−−−−−−−−+
p: [Ref21354]−−−−−−−−−−−−−−−−−−−−−−−−−−−>|    (Person)      |
                                         +−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−+
                                         | name: [Ref54312] |−−−>|  (String)  |
                                         +−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−+
                                                                 | "studName" |
                                                                 +−−−−−−−−−−−−+

(Leaving out many details; the string, for instance, actually refers to a char[] array elsewhere and has several other fields.)

The Ref11325 in c, Ref21354 in p, and Ref54312 in p's name field are just there to show that they contain references; we never see a reference's actual value.

Then when you do:

c.p = p;

you have (only change is c's p, of course):

                 +−−−−−−−−−−−−−−−−−+
c: [Ref11325]−−−>|   (Container)   |
                 +−−−−−−−−−−−−−−−−−+
                 | className: null |
                 | p: [Ref21354]   |−−+
                 +−−−−−−−−−−−−−−−−−+  |
                                      |
                                      \    +−−−−−−−−−−−−−−−−−−+
p: [Ref21354]−−−−−−−−−−−−−−−−−−−−−−−−−−+−−>|    (Person)      |
                                           +−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−+
                                           | name: [Ref54312] |−−−>|  (String)  |
                                           +−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−+
                                                                   | "studName" |
                                                                   +−−−−−−−−−−−−+

See how Ref21354 was copied from p to c.p.

Then finally, when you do:

p = new Person();

you have this:

                 +−−−−−−−−−−−−−−−−−+
c: [Ref11325]−−−>|   (Container)   |
                 +−−−−−−−−−−−−−−−−−+
                 | className: null |       +−−−−−−−−−−−−−−−−−−+                       
                 | p: [Ref21354]   |−−−−−−>|    (Person)      |                       
                 +−−−−−−−−−−−−−−−−−+       +−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−+
                                           | name: [Ref54312] |−−−>|  (String)  |
                                           +−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−−−+
                                                                   | "studName" |
                                                                   +−−−−−−−−−−−−+

                                           +−−−−−−−−−−−−−−−−−+
p: [Ref34851]−−−−−−−−−−−−−−−−−−−−−−−−−−−−−>|    (Person)     |
                                           +−−−−−−−−−−−−−−−−−+
                                           | name: null      |
                                           +−−−−−−−−−−−−−−−−−+

p now contains a new reference, but that has no effect at all on c.p.


* "Pass-by-value" and "pass-by-reference" are terms of art and relate to what happens when you pass a variable into a function:

doSomething(someVariable);

In pass-by-value, the value of someVariable is passed into doSomething. In pass-by-reference, a reference to the someVariable variable is passed into doSomething. In pass-by-reference, the function can reach out and change the contents of the variable. In pass-by-value, it cannot.

The word "reference" in "pass-by-reference" has nothing to do with the word "reference" in object references, it's just two things defined using the same overloaded word. The "reference" in pass-by-reference is a reference to a variable, not an object.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
1

During my preparation to the OCA and OCP certification I found a very good advice - to paint each relation on the paper.

In your case relations between objects, values and references will be following. enter image description here

In operation #5 you will remove connection which was created during operation #2 (see dotted line).

Illustrations should help more than any explanation in words. Hope this will help.

0

When you do this:

Person p = new Person();

An instance of Person is created on the heap (first instance), and exists as long as something references it. p is a variable on the stack, and its value is a reference to that instance.

When you do this:

p = new Person();

An instance of Person is again created on the heap (second instance). The local variable p is assigned the new value of a reference to that instance. The previous instance (first instance) no longer has any reference to it, and is garbage collected.

When you do this:

c.p = new Person();

An instance of Person is again created on the heap (third instance). The local variable p was unaffected of course, so the "second instance" is unaffected as well. The local variable c also still points to an instance of Class on the heap, which is still its first instance. That instance includes a class-level variable called p, which now follows the same rules as the second example above. It previously pointed to an instance of Person on the heap, and its value is updated to point to a new instance (third instance).

The "value" in these variables is simply a kind of address in the heap where the object exists.

David
  • 208,112
  • 36
  • 198
  • 279