Lesson: Passing Reference Parameters

Overview: 
Explore the difference between passing primitive parameters and reference parameters.
Objectives: 

Understand the difference in behavior of primitive data type parameters and reference data type parameters in methods.

Content: 

In the lesson on passing parameters we learned that parameters are passed by value, that is, a copy of the calling code's value is given to the method for it's internal use only. Reference (object) parameters work the same way but there is an important distinction to make in how reference parameters are used in methods.

For this lesson, we are going to use the String object and a new object called StringBuffer. StringBuffer is part of the standard Java API library. String objects are immutable, meaning that once they are created they can't be changed. So if we do this:

The first statement created a String object with the value "abc". Java allocates computer memory and places a String object containing the characters abc into that memory and places a reference (pointer) to that memory location in the variable myString. The second statement creates a new String object with the value "xyz" and places a reference to that new object in the same variable, myString. At this point the reference (pointer) to the original object containing "abc" is now no longer available to us. "abc" still exists but we overlayed the reference to "abc" with a reference to "xyz". The String object "abc" is now orphaned, meaning it no longer is connected to our program and will be discarded by Java. This is called garbage collection.

Note that the String object has no methods that change it's contents. Strings are modified by making a new String object from the old one. Here is another example:

Here again, we did not modify the string "abc" with the second statement. A new string is created containing the characters myString references, "abc" in this case, and concatenates the string "xyz" to create a new string containing "abcxyz" and a reference to this new string is stored in myString. The original string containing "abc" is no longer referenced by this code and will be garbage collected.

Now the StringBuffer class does provide methods to change it's contents without creating a new object. So if we do this:

The first statement creates a new StringBuffer object and places "abc" into it. The second statement calls a method on the StringBuffer object that adds "xyz" to the "abc" already inside the StringBuffer object without creating a new object. When done, mySB is still a reference to the same StringBuffer object which now contains "abcxyz".

So with all of that out of the way we can discuss the nuances of using reference parameters in a method.

Consider this example:

The intent of the method is to append "xyz" to whatever is in the String str. After the call to myMethod(), what is in the String myStr? The answer is "abc". Why? The parameter myStr is passed as a copy of the reference to the myStr object placed into the method variable str. In the method, we change the contents of str. Str now points to a new String object containing "abcxyz". However, this new String object reference is not passed back to the calling code. Now consider this example:

After the call to myMethod1(), what does mySB contain? The answer is "abcxyz". Why? Because we called a method on the mySB object using the reference copy passed into the method's sb variable. With the append method, we change the internal state of the mySB object and that is reflected immediately in mySB.

After the call to myMethod2(), what does mySB contain? The answer is still "abcxyz". Why? Because we made a mistake and said new in the method, which creates a new StringBuffer object and stores the reference to it in sb. For the rest of the method sb contains a reference to "xyz". Since we changed the object that sb points to, the method lost its pointer to mySB and can't reference it after that point. Note that at the end of the method, sb will be released since variables created in a method only exist while that method is executing.

As a final point, in our first example the method wanted to append "xyz" to whatever string was passed into it, but it does not change the string that was passed in. Here is how you could fix that method:

Here the method concatenates the two strings using the + operator and creates a new string with it's reference deposited into str. The method then returns this new string reference and the calling code replaces the original string reference with the returned string reference and so myStr ends up pointing to the string "abcxyz".

A final note about garbage collection. In the last example, str will go out of scope when the method ends. You might think the new string pointed to by str would be orphaned and then garbage collected. However, since a reference to the actual string object in memory was passed back to the calling program and placed into myStr, the string object is not orphaned and will continue to exist. When a reference to an object is stored in a variable, the JVM keeps track of that by incrementing the object's reference count. When a variable that references an object goes out of scope or the variable is to have something new stored in it, the JVM decrements the object's reference count. This is how the JVM knows when an object is orphaned, when its reference count goes to zero (no variable is pointing to it). When no variable is pointing to an object in memory, that object is no longer accessible and the memory can be released.

Here are the examples on CodingGround.

 

Navigation: