Pass by value vs. pass by reference

The Concept

of pass-by-value and pass-by-reference are used to describe how parameters to a function will be handled internally during that function’s execution. The concept is, or at least should be very clear by now, yet its implementation on Java is still causing debate in dev communities. I know for a fact that Java is strictly using pass-by-value for both primitives and object references, yet the actual behavior for object references can be confusing.

private void renameMyDog( Dog spike ) {
	spike = new Dog();
	spike.setName( "Rover" );
}

AssertEquals( "Rover", spike.getName() );

org.junit.ComparisonFailure: expected:[“Rover”] but was:[“Spike”]

If you’ve ever found yourself in that situation then this article is for you.

The Problem

arises when people assume that Java behaves the same way as other, prior programing languages and the way they handle pointers. I don’t have much experience with those other languages so am going to discuss this from Java’s perspective only. Let’s settle this once for all.

Definitions

Pass-by-value: The passed-in parameter is getting copied on the stack memory allocated for that specific method. That means that new instance with different memory address is created. Since, in Java the stack memory is going to exist as long as the method is running, meaning that when the method terminates the stack memory will be cleaned of any data and reallocated for future use, it’s easy imagine that once the method exist all changes made to any objects in it will be disregarded. So the passed-in parameter will actually remain untouched.

Pass-by-reference: Here, the passed-in parameter is treated as reference to an object that exists in a different memory location than the method’s stack and will not get reallocated after the invoked method terminates. Basically the calling method will live longer than the calee. That way any change made on the reference will also change the object that this reference is pointing to.

Java Memory Organization

can tell you where objects are being created in-memory and how long will they live. When it comes to method execution there are two kinds of memory spaces that you should be concerned with: the Heap and the Stack. I won’t go too deep on the memory model right now, so you can keep you focus on the main topic.

The Heap:

“The Java Virtual Machine has a heap that is shared among all Java Virtual Machine threads. The heap is the run-time data area from which memory for all class instances and arrays is allocated.” – according to Oracle documentation

The Heap is the general memory area that manages available memory and triggers garbage collections to remove unused objects. It’s shared among all classes and so it’s perfect location for global variables. Another important point is that all objects are created on the Heap, even if declared inside methods.

The Stack:

“Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread…it holds local variables and partial results, and plays a part in method invocation and return.” – according to Oracle documentation

The Stack memory area is created and terminated per method. It contains all primitive types that are created or passed-in the method. There can be multiple stack memory spaces depending on the number of methods that are executed at that time. If the stack space for method runs out of memory, you’ll get the infamous java.lang.StackOverFlowError.

Java Behavior

supports only two possible scenarios that may occur in Java when passing parameters to a method: passing primitive type and passing object reference.

Passing primitive types according to Oracle’s description:

“Primitive arguments, such as an int or a double, are passed into methods by value. This means that any changes to the values of the parameters exist only within the scope of the method. When the method returns, the parameters are gone and any changes to them are lost.”

There’s nothing special here. This case works exactly as expected when one realizes that there are no such things as references to primitive types. So any primitive type that gets passed-into a method will definitely get copied on the stack memory leaving the original value intact once the invoked method terminates.

Consider the following example:

public static void main( String[] args ) {
	int coffeesPerDay = 2;

	System.out.println( String.format( "Coffees per day are set to: %d", coffeesPerDay ) );

	drinkOneMoreCoffeeToday( coffeesPerDay );

	System.out.println( String.format( "Coffees per day are still set to: %d", coffeesPerDay ) );
}

private static void drinkOneMoreCoffeeToday( int coffeesPerDay ) {
	coffeesPerDay += 1;
}

Result of running that code:

Coffees per day are set to: 2
Coffees per day are still set to: 2

There you have it, written and proven. When passing primitive types the original value remains unchanged because, under the hood, JVM is copying that value into new, local variable at new, local memory space, thus leaving the original memory space untouched.

Passing will work the same way for all Java primitive types, as illustrated on next overly complicated example. Feel free to skip it if it’s too much:

public static void main( String[] args ) {
	byte transportsPerDay = 2;
	short workHoursPerDay = 8;
	int coffeesPerDay = 2;
	long fitnessPerWeek = 2;
	float temperatureAtNoonCelcius = 20.5f;
	double spendingPerDay = 10.00d;
	boolean isHappyOverall = true;
	char firstCharOfName = 'G';

	printValues( transportsPerDay, workHoursPerDay, coffeesPerDay, fitnessPerWeek, temperatureAtNoonCelcius,
 			spendingPerDay, isHappyOverall, firstCharOfName );

	changePrimitiveTypes( transportsPerDay, workHoursPerDay, coffeesPerDay, fitnessPerWeek,
			temperatureAtNoonCelcius, spendingPerDay, isHappyOverall, firstCharOfName );

	printValues( transportsPerDay, workHoursPerDay, coffeesPerDay, fitnessPerWeek, temperatureAtNoonCelcius,
			spendingPerDay, isHappyOverall, firstCharOfName );
}

private static void changePrimitiveTypes( byte transportsPerDay, short workHoursPerDay, int coffeesPerDay, 
	long fitnessPerWeek, float temperatureAtNoonCelcius, double spendingPerDay, boolean isHappyOverall,
	char firstCharOfName ) {
	
	transportsPerDay = 4;
	workHoursPerDay = 4;
	coffeesPerDay = 4;
	fitnessPerWeek = 4; // Yeah, I wish!
	temperatureAtNoonCelcius = 15.5f;
	spendingPerDay = 15.00d;
	isHappyOverall = false;
	firstCharOfName = 'E';
}

private static void printValues( byte transportsPerDay, short workHoursPerDay, int coffeesPerDay, 
	long fitnessPerWeek, float temperatureAtNoonCelcius, double spendingPerDay, boolean isHappyOverall,
	char firstCharOfName ) {

	System.out.println( "Transports per day: " + transportsPerDay );
	System.out.println( "Working hours per day: " + workHoursPerDay );
	System.out.println( "Coffees per day: " + coffeesPerDay );
	System.out.println( "Fitness per week: " + fitnessPerWeek );
	System.out.println( "Temperature at noon in Celsius: " + temperatureAtNoonCelcius );
	System.out.println( "Spending per day: " + spendingPerDay );
	System.out.println( "I’m happy overall: " + isHappyOverall );
	System.out.println( "First char of name: " + firstCharOfName );
	System.out.println();
}

Result of running that code:

Transports per day: 2
Working hours per day: 8
Coffees per day: 2
Fitness per week: 2
Temperature at noon in Celsius: 20.5
Spending per day: 10.0
I’m happy overall: true
First char of name: G

Transports per day: 2
Working hours per day: 8
Coffees per day: 2
Fitness per week: 2
Temperature at noon in Celsius: 20.5
Spending per day: 10.0
I’m happy overall: true
First char of name: G

One last thing that I like to mention here is that having methods with more that 2-3 parameters is bad practice because it’s affecting readability, logic, complexity, and refactoring of the code. I’m allowing it for sake of this explanation. Otherwise I would have surrendered myself to the authorities by now cause that’s a crime!

Passing object references according to Oracle’s description:

“Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object’s fields can be changed in the method, if they have the proper access level.”

Here’s the tricky part. When object reference is passed-in, it’s not getting copied to its own place on the stack memory like the primitive types. Instead it’s getting directly used, so any change made to it will change the object at the other end of that reference. That’s the main difference between passing primitives and references and that is also the main source of confusion and here is why:
When passing-in a reference and changing properties of the object that is on the other end of the reference – changes will remain even after the called method terminates.

private static void changeCircleColorToBlack( Circle whiteCircle ) {
	whiteCircle.setColor( "Black" );
}

public static void main( String[] args ) {
	Circle whiteCircle = new Circle( "White" );

	System.out.println( whiteCircle.getColor() );

	changeCircleColorToBlack( whiteCircle );

	System.out.println( whiteCircle.getColor() );
}

Result of running that code:

White
Black

However, if you assign the passed-in reference to new object the reference will no longer point to the originally passed-in object. The new object will have it’s own memory address in the Heap, different than the passed-in object’s memory address. Ultimately any changes made after the new keyword will be discarded, because this time there is a different object at the end of the reference.Once the method terminates, the passed-in reference will return to point to the original object and since there is no reference to the newly created object it will simply be garbage collected.

private static void changeCircleColorToBlack( Circle whiteCircle ) {
	whiteCircle.setColor( "Black" );
}

private static void createNewCircle( Circle whiteCircle ) {
	whiteCircle.setColor( "Black" );

	whiteCircle = new Circle( "White" );
}

public static void main( String[] args ) {
	Circle whiteCircle = new Circle( "White" );

	System.out.println( whiteCircle.getColor() );

	changeCircleColorToBlack( whiteCircle );

	System.out.println( whiteCircle.getColor() );

	createNewCircle( whiteCircle );

	System.out.println( whiteCircle.getColor() );
}

Result of running that code:

White
Black
Black

In this example, new Circle is being assigned to the whiteCircle reference inside createNewCircle method with line “Circle whiteCircle = new Circle( “White” );” So from this point on, any change will be applied to the new object which will get garbage collected after createNewCircle terminates, leaving the original whiteCircle intact.

The curious case of java.lang.String

String is a object class and not a primitive type. So when passed-in it should behave like the whiteCircle object. Actually, no. String may be a object class but it’s also immutable, which means that no further mutations/changes are allowed. So when you change a String the JVM actually create a new one behind the scenes and assign it to the same reference.
It’s now easy to see that any change made on a passed-in String object reference will be garbage collected once the method terminates, not only because of the way Java handles passed-in references, but also because of String’s immutable nature.

public static void main( String[] args ) {
	String text = "The object that I point to cannot be edited";

	System.out.println( text );

	changeMyString( text );

	System.out.println( text );
}

private static void changeMyString( String text ) {
	text = "Attempt to change an immutable object";
}

Result of running that code:

The object that I point to cannot be edited
The object that I point to cannot be edited

Links

Guru99’s Youtube channel has a great video on Heap and Stack memory allocation when calling nested functions.

If you need more info and analysis on the difference between Pass-by-value and Pass-by-reference check out JavaDude’s blog post.

Oracle’s documentation on Heap and Stack memory.

Java documentation on passing parameters into methods.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s