Win a copy of Mesos in Action this week in the Cloud/Virtualizaton forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Interesting problem in Java with pass by reference

 
Bill White
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I understand that when you pass an object in Java it is automatically passed by reference. So any change made in the method it was passed to is made to the object that was passed.
Here is some test code:
Client one = client_ImageManager1.createClient(clientOne, clientOneMac);
Client two = client_ImageManager1.createClient(clientTwo, clientTwoMac);
Client three = one;
System.out.println(one.equals(three));
three.setDescription("TEST");
System.out.println(one.getDescription());
client_ImageManager1.changeRef(three);

System.out.println(one.getDescription());
System.out.println(three.getDescription());
here is changeRef()
public void changeRef(Client test)
{
Client t = test;
t.setDescription("F");
t = null;
test = null;
}
my expected output was: true Test then a NPE
what I got was: true test F F
So, is this because the Garbage Collector has not cleaned up the memory yet? If so, that seems BAD.
Looking to the experts to clarify this.
Thank You
 
Cindy Glass
"The Hood"
Sheriff
Posts: 8521
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No - it is doing what it is supposed to do.
You have 5 variables here:
one
two
three
test
t
but you only have 2 objects:
The one that "one" originally referenced and the one that "two" originally referenced.
one refereces obj1
two references obj2
then you point variable three at the same object as variable one so
three references obj1
You set the description of obj1 to 'test' and print it out.

The you pass a copy of the reference that three is holding to your method - so you pass in a reference to obj1
test references obj1
Then you create variable t and point it at the same object that test is referencing so
t references obj1
You set the description of the object that t is referecing (obj1) to 'F'.
Then you free up variable test and variable t. That does not get rid of the object that they reference because "one" still holds a referecne to obj1.
When you return from you method you print the description of the object referenced by variable "one" which is obj1 which now holds an 'F'.
Then you print the description of the object referenced by variable "three" which is also obj1 which of course still holds an 'F'.
[ April 23, 2003: Message edited by: Cindy Glass ]
 
Michael Morris
Ranch Hand
Posts: 3451
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

I understand that when you pass an object in Java it is automatically passed by reference.

Not true. All paramaters in Java are passed by value. Whether it is a primitive like int or a reference to an Object, a copy is passed into the method. It is important to remember that a reference is not an object, it is a means of locating an object only, sort of like a C pointer, but bound to a single object.
 
Greg Charles
Sheriff
Posts: 2985
12
Firefox Browser IntelliJ IDE Java Mac Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No, it has nothing to do with the garbage collector. You are right though that objects are passed by reference in Java. Let's look at it step by step.
You create a Client object and set a reference to it:
Client one = new Client();
(I'm simplifying here for clarity.)
You then call a method using your Client object as parameter. This creates a second reference to the same client object.
changeRef(one);
You are not passing a reference to "one", but to the object that "one" refers to. You can also think of it as passing "one" by value, but "one" is itself a reference.
Inside the method, you create a third reference to the object.
Client t = test;
Finally, you set the second and third reference to null. That doesn't change the object in any way. It just means that "test" and "t" no longer refer to it. In this case, that is sort of meaningless because the method returns immediately. When that happens, those references cease to exist anyway. However, "one" still exists and still refers to the same client object. Nothing you can do in the method can change that. The Client object will not be garbage collected until all references to it are either gone or pointing somewhere else.
 
Greg Charles
Sheriff
Posts: 2985
12
Firefox Browser IntelliJ IDE Java Mac Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Wow, a triple simulpost. We obviously need more people asking questions about first principles in here!
 
Joshi Thomas
Greenhorn
Posts: 7
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Objects are also passed by value. You can change the state of the object (often confused with passing with reference) but you cannot set the object set to null. Java does not support passing objects by reference.
 
Bill White
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Micheal,
Thank you, I stand corrected. The value of the reference is passed.
But in the end, the same thing as "Passing by reference" happens. That is, changes made in the method are reflected onto all objects that point to that reference. Correct?
 
Nilesh Pereira
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just to clarify things:
Java copies and passes the reference by value, not the object. Thus, method manipulation will alter the objects, since the references point to the original objects. But since the references are copies, swaps will fail.
 
Bill White
Ranch Hand
Posts: 82
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes. I tested this further with
Client a = new Client();
Client b = a;
b.setDescription("Some String");
a = null;
System.out.println(b.getDescription());
And got back Some String. For 2 years I have been programming Java professionaly under the assumption that b would have been set to null.
Thankfully, I have yet to be bit by this. I now have a new understanding and appreciation of how Java deals with passing objects and the consequences of such.
Thank You all.
 
Michael Morris
Ranch Hand
Posts: 3451
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

But in the end, the same thing as "Passing by reference" happens.

Not exactly, as Nilesh and Joshi point out. Yes, you can certainly change the state of the object referenced in the mehtod, but changing the value of the parameter inside the method has no effect on the reference in the calling object, which it would in a true call by reference, like using the & (address of) operator or a pointer in C.
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I agree with Michael, Nilesh and Joshi. If Java were truly "pass by reference" (as the term is understood by users of other laguages such as C) then you'd be able to write code like this

and you'd see
x = bar
y = foo
But you don't, since the swap method only gets copies of the values of the references - it can't change the original references themselves. And since "foo" and "bar" are immutable strings, there is absolutely no way you can rewrite swap() to exchange the data between x and y. If Java were really "pass by reference", the swap() method would work.
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
By these definations, C does not implement pass by reference either! The C method to do Jim's code:

This will produce the same output as in Java (x = foo, y = bar) since the swap function gets a copy of the pointers and not the original pointers themselves.
This is understood to be "pass by reference" in C, since you could modify the value of the strings in the functions. Why is this not "pass by reference" in Java? Or am I misunderstanding "pass by reference" in C?
[ April 23, 2003: Message edited by: Joel McNary ]
 
Nilesh Pereira
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, if you used references it would've worked
Your swap method declaration should read:
void swap(void &a, void &b)
...
[ April 23, 2003: Message edited by: Nilesh Pereira ]
 
Thomas Paul
mister krabs
Ranch Hand
Posts: 13974
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Java always does pass by value. C# supports pass by value as the default and pass by reference.
Look at this:

Guess what prints... "Java".
The C# version:

This will print C#.
[ April 23, 2003: Message edited by: Thomas Paul ]
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

and call swap(&x, &y) to get the x = bar y = foo result. This technique is dereferencing the variables, which is not directly supported by Java, but my assertion is still that my prior attempt is "pass by reference".
[ April 23, 2003: Message edited by: Joel McNary ]
 
Thomas Paul
mister krabs
Ranch Hand
Posts: 13974
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Joel McNary:
This technique is dereferencing the variables, which is not directly supported by Java, but my assertion is still that my prior attempt is "pass by reference".

Pass by reference is what C# does in my example above. Java can not do anything like that.
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Thomas Paul:

The C# version:
<snip>
This will print C#.
[ April 23, 2003: Message edited by: Thomas Paul ]

Interesting example. Does this mean that C does not support pass by reference as understood by C#? Or is the ability to dereference your references required to be termed "pass by reference"?
[ April 23, 2003: Message edited by: Joel McNary ]
 
Nilesh Pereira
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry, that was C++ syntax. My bad!
In C, you pass the reference in your
swap method invocation, and use the
pointer in your swap method.
for example:

The bottom line is that in C/C++ you can choose to pass by value OR by reference... in java you can ONLY pass by value.
[ April 23, 2003: Message edited by: Nilesh Pereira ]
 
Jamie Robertson
Ranch Hand
Posts: 1879
MySQL Database Suse
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I found that this article has a good explanation.
Jamie
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmm...I had no idea that C++ supported that syntax. I've never used it!
When I code in C/C++, I never create objects; in create pointers to objects and then new / malloc the objects themselves. I then pass my pointers to functions. I had always believed that this was termed "pass by reference" because I was passing not the Object itself but rather a reference to the object. This is exactly the same thing that is done in Java, except that we don't have the option of creating an object directly; we have to use new.
Because of how I code my C/C++, I've never been confused as to what Java is doing when I work with objects. I was confused because they term "pass by value" doing the same thing in Java that I term "pass by reference" in C/C++.
Examples: (Given a class SomeList which can add a string (char*) and randomizes the elements through a function randomizeMe)
1:

So my question: In this example, is this pass by value or reference? In Java, the analous code replaces "->" with "." and drops the "*"s and is termed "pass by value," which leads me to believe that what I am doing in my above example is also "pass by value", even though I thought that it was "pass by reference"
2:

This is unquestionably pass by reference; or at least how I learned pass by reference. The list will be randomized.
3:

and this is pass by value. The list would never be randomized.
If 2 is pass by reference, why isn't 1? And if 1 is what Java does, why don't we call what Java does pass by reference?
As I said, I'm not confused by what happens, just confused about why we call it what we do....
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"and this is pass by value. The list would never be randomized."
Of couse, I meant that the List in the main method would never be randomized.
Thanks for the article, Jamie. It does state that C does not support treu pass by reference, but rather can simulate it through & and dereferencing in the called method.
Since I've never used the C++ ability to declare a &x in my formal parameters, I guess I've never done true pass by reference!
 
Nilesh Pereira
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Apparently I misread your post. Sorry.
[ April 23, 2003: Message edited by: Nilesh Pereira ]
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic