Hi. This is probably a bit of a noob question, about the use of 'pass by reference' in java. It is my understanding that pass-by-reference is the default for all function calls in java. However, i have written some code where i want to alter the value of an object passed to a method in another class, and while changing the object seems to work in the remote class, the value of the object is not changed in the calling environment. Here is the offending code:
(FYI - this code is building a DOM tree from a recordset (to be written out into an XML file at the end of the process). The 'row' object is part of a db wrapper class, and essentially holds the column names and values for the current row of the query) You can see in the 'append' method that i set the Element 'spec_node' to null, but this does not happen in the calling environment. What am i missing? Thanks for any help. Robin
Java actually uses pass by value. Some of these values are references to objects. Therefore, if in a called method, you change the contents of an object -- i.e., call a method which mutates the object in some way -- then the calling method will see the changes in the object it passed in. But if in the called method, you assign the argument variable to point to a new object, then the called method will have no idea whatsoever that this has happened. If this doesn't make sense, then you could read this and hopefully it will clear things up. The variables that you want to change from the called method should probably be made into member variables of tsiTownAppender -- then they can be shared by both methods that use them.
i won't swear i'm correct, but here's what I think is happening (i'm still pretty new to java myself, so fogive me if i'm wrong). your calling routine has a reference to an object. in other words, town_node points to something somewhere. when you pass it into the routine, you create another reference that points to the same place. you have two "pointers" to the object. and, in this case, they seem to be called the same thing, but we can tell them apart by scoping rules. if you use the pointer to change the object, it's changed in both locations. however, what you are doing with spec_node = null; is saying "take my local reference to the object, and don't point it there anymore, point it to nothing". the local copy looks like there's nothing there, but the copy in the calling routine still points to it. does that make sense? however, when you say
There are only two hard things in computer science: cache invalidation, naming things, and off-by-one errors
The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Java ALWAYS passes a copy of the thing you are sending along, aka "by value". On return, it throws away the copy. With primitives this makes perfect sense. If you pass an int parameter, Java makes a copy of the int. If the called method modifies the parameter, it modifies the copy and not the original. So the simple rule is the called method cannot modify the caller's variable. With objects it's a bit trickier because the thing being passed is a "pointer" to an object. So it passes a copy of the pointer. Now it points to the same object, so if the called method modifies the object, it modifies the original object, so upon return the caller sees the changes. What the called routine cannot do is make the pointer point to a different object. That would be modifying the thing that was passed and we already said the called method can't do that. That usually makes good sense, except for String and other immutable objects. The deal with String is any operation that makes a change gives you a new String. So aString = aString.substr(2) doesn't change the aString object that the pointer points to, it creates a new object. And we can't change the caller's pointer to point to the new one, so the caller does not see the change.
This is a very common question and grokking the answer is a Java learning milestone. Hope that helped!
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Joined: Sep 17, 2002
Many Thanks for all your help. I have looked at all the resources that have been suggested, and i think i'm starting to understand. The implications of this discussion seem to suggest that my approach was wrong, so i was wondering if you might offer me any alternative patterns. Maybe there's a way of altering the code to mimic pass-by-reference (as i origionally understood it), or do i have to re-think from the ground up?? What i'm trying to do is create an 'index' in XML that will be processed with an XSL stylesheet, then turned into a PDF by Apache FOP. Here is a illustration of the Schema for this index:
In the calling environment i have set up Elements for <townspecindex/>, <town/>, <specialty/> and <consultant/>. I have also set up 3 'appender' classes (the code in my previous post is one such class). So, the idea is that i loop round, passing each of the data Elements to each of the appenders each time:
So, each appender has logic in it to append the right child at the right time, i.e. when the specialty changes in the recordset, the specAppender() will append the old specialty element to the town_node it has been given, and return a new specialty node (there is a private 'last spec' member variable that triggers this for a new specialty). If pass-by-reference is not available in Java to make this kind of approach possible, what other pattern does java use to achive the same thing? I could just cut and past all of the code from the external classes in to the calling environment, but that doesn't seem very object oriented to me!!! Thanks once again for all your help - i hope i have explained this well enough!! Robin