Java pass-by-reference and pass-by-value

The question often arises, “Does Java pass-by-reference or does it pass-by-value?” meaning when an argument is passed to a method in Java, is it the memory address of the variable given to the method, or the value of the variable that is passed to the method. What happens when you change the values of the arguments passed to a method?

Without getting into discussions about the virtues of functional programming versus traditional object oriented programming, let’s answer the pass-by-reference or pass-by-value question.

Java uses pass-by-value. This gets a little confusing with objects, but we’ll stick to primitives for the moment. Java passes copies of variable values to methods. When passing primitives to methods, such as ints and bytes, any changes to the values of the method arguments are only of local scope to the method.

For example, in the following code, a primitive named myInt is passed to the changeTheInt() method. The method proceeds to attempt to change the value of argument i. However, even though i‘s value changes, this does not affect the value of myInt. The changed value is kept in the scope of the local method because a copy of the original myInt variable’s value was passed to the method, not the actual myInt variable.

package com.tgenedavis.values;

public class PrimitivePassing {

	private static int myInt = 42;

	/**
	 * Attempts unsuccessfully to change the original myInt value.
	 */
	private static void changeTheInt( int i ) {
		i = 10;
		System.out.println( "i = " + i );
	}

	/**
	 * prints ...
	 * 
	 * myInt = 42
	 * i = 10
	 * myInt = 42
	 */
	public static void main(String[] args) {

		System.out.println( "myInt = " + myInt );
		changeTheInt( myInt );
		System.out.println( "myInt = " + myInt );

	}
}

Understanding pass-by-value in Java when it comes to primitives is easy. Understanding pass-by-value when it comes to objects in Java is a bit more challenging. Using a couple of examples will help.

First, let’s start with a simple object called Clouds. Clouds has the singular purpose of keeping track of how many clouds are in the sky. The constructor takes an int for initializing the number of clouds in the sky. Clouds also provides methods for changing the number of clouds in the sky, and printing the number of clouds in the sky.

package com.tgenedavis.values;

public class Clouds {
	private int numberOfClouds;

	//single parameter constructor
	public Clouds(int count) {
		numberOfClouds = count;
	}

	//setter for numberOfClouds
	public void setNumberOfClouds(int numberOfClouds) {
		this.numberOfClouds = numberOfClouds;
	}

	//print the number of clouds in Clouds object
	public void printCloudCount() {
		System.out.println("Cloud count is " + numberOfClouds);
	}
}

So let’s get on with testing the behavior of Java when passing Clouds objects to methods.

As I mentioned earlier, everything is passed-by-value in Java. So, when you construct an object and pass the object to a method, setting the method argument equal to a different object does not change the value of the original object that was passed to the method. Think about this and you will realize the behavior is exactly like that of primitives that are passed by value to methods.

The following test illustrates that behavior. A Clouds object is passed to the changingReference() method. The method argument of clds is set equal to a new Clouds object, but the original clouds variable in the main() method remains unaffected.

package com.tgenedavis.values;

public class TestPassing {

	/**
	 * Testing changing the value of a reference ton object.
	 */
	private static void changingReference( Clouds clds ) {
		clds = new Clouds( 5 );
		clds.printCloudCount();
	}

	/**
	 * Prints ...
	 * Cloud count is 3
	 * Cloud count is 5
	 * Cloud count is 3
	 */
	public static void main(String[] args) {
		Clouds clouds = new Clouds( 3 );
		clouds.printCloudCount();

		changingReference( clouds );

		clouds.printCloudCount();
	}
}

Now comes the tricky part. What are objects in Java? What actually gets passed-by-value to methods when an object is passed to a Java method?

When you look at the value of a primitive in Java’s memory, it is the value of the variable. However, when you look at the value of a Java object in Java’s memory it is the address to the real location of the object. In C terms, the value found in memory of a Java object is a pointer to the actual object’s location.

I know I just lost a whole bunch of you. Sorry. Let’s try that again.

Java stores the smallest descriptions of it’s variables possible as their actual value. This is for performance reasons. In the case of primitives, the smallest value possible is the actual value of the primitive. In the case of objects, the smallest value possible is the memory address of the actual object. That way, when copying an object to a method, the guts of the object (such as it’s attributes) don’t get copied. The address of the object gets copies.

That’s probably still confusing, but all you really need to remember is the result of this. An object that is passed to a method behaves like a pass-by-reference, because a copy of the object’s reference is passed to Java methods. Any calls to methods or changes of attributes of an object that is passed to a method results in changes to the attributes or calls to the original object.

For example, calling the clds object’s setter in the following test results in a change to the clouds object’s attribute.

package com.tgenedavis.values;

public class TestPassing {

	/**
	 * Testing changing the value within a reference to an object.
	 */
	private static void settingValue( Clouds clds ) {
		clds.setNumberOfClouds( 9 );
		clds.printCloudCount();
	}

	/**
	 * Prints ...
	 * Cloud count is 3
	 * Cloud count is 9
	 * Cloud count is 9
	 */
	public static void main(String[] args) {
		Clouds clouds = new Clouds( 3 );

		clouds.printCloudCount();

		settingValue( clouds );

		clouds.printCloudCount();
	}
}

Objects, like primitives, are passed-by-value in Java. However, the value copied and passed in the case of objects is the memory location, not the full object. For convenience, you can think of Java objects as passed-by-reference. Remember though, if you try setting objects equal to new objects inside methods, the change will be scoped only to the method. You cannot change the original object to a new object inside a method. You need to stick to calling its methods and changing its attributes to make changes to the original object.