When each object is created, member variable i is initialized to 10.
Method amethod() sets its own local variable i to 99. It then creates the first ValHold1 object and changes that object's member variable i from 0 to 30. amethod() then calls method another() with two arguments, a reference to the first ValHold1 object and the value 99 from amethod's local variable i. These are copied from amethod()'s local reference variable v and amethod()'s local int variable i.
Method another() gets two parameters, the reference to the first ValHold1 object and the int value 99.
Formal parameters are pretty much like local variables, so another() can now change its formal parameter i from 99 to 0 without affecting amethod's local variable i, which stays at 99.
another() then changes the first ValHold1 object's member variable i from 30 to 20. It then creates the second ValHold1 object and stores it's reference in vh. The second Valhold1 object's member variable i is automatically initialized to 10.
another() then changes parameter v from referencing the first ValHold1 object to referencing the second ValHold1 object [v=vh;]. This does not affect the local reference variable v in amethod().
another() then uses parameter v to access the second ValHold1 object's member variable i, which is still 10, and it prints the 10, a space, and another()'s parameter i, which another() had changed to 0.
Finally, another() returns to amethod(), which uses it local reference variable v to access the first ValHold1 object's member variable i, which another() had changed to 20. The 20 is printed and we are done.
Of course, most of the confusion was deliberately created by having two member variables, one local variable, and one formal parameter, all named i. [ December 14, 2004: Message edited by: Mike Gershman ]
In the first method, we use "new" to create an object of the type ValHold1, referenced by the local variable v.
When we call another(v, i), we are passing a reference to that object. Method arguments are copies, and they are local to the method. So we now have a local variable v in the first method, and another local variable v in the second method. But although these are separate local variables, they both reference the same object (the one created with "new" above).
So when we invoke v.i=20 (using the reference copy in the second method), this sets i=20 in the object itself. So if the first method were to reference that object (with its own local variable v), the value of v.i will be 20.
After modifying the original instance of ValHold1, the second method also creates a new instance of ValHold1, referenced by vh. Then, it sets v=vh. This simply reassigns the local variable v in the second method, so that it references the newly created object instead of the original object.
Note, however, that this has no effect on the first method's local variable v, which still references the original object.
So... When the second method prints v.i, it is printing the value of i in the newly created instance (also referenced by vh), so this is 10. When the second method prints i, it prints the value of the local variable i, so this is 0. Then when the first method prints v.i, it is printing the value of i in the original instance, which is now 20 because the object itself was modified (by way of the reference passed to the second method). [ December 14, 2004: Message edited by: marc weber ]
"We're kind of on the level of crossword puzzle writers... And no one ever goes to them and gives them an award." ~Joe Strummer sscce.org
In cases like this and in cases of garbage collection I find it helps a lot to draw a picture to illustrate what's going on. For ValueHolder, you would have one object with two references to it. The object is then changed, and then one of the references changes to point to a different object.