The Myth of Pass-by-Reference in Java

…and the difference between reassigning a reference and mutating the object it refers to

Let’s take an example —

Assume a linked list with a pointer ptr defined. (I’ll casually use the word “pointer” throughout this article because that’s how linked-list diagrams are usually described. Technically, Java has references, not pointers.)

Linked List with Nodes (Is this correct?)

Now, look at the following code snippet.

void main() {
LinkedList linkedList = new LinkedList();
LinkedList.Node ptr = linkedList.addNode(1);
linkedList.addNode(2);
linkedList.addNode(3);
linkedList.addNode(4);

System.out.println("Current pointer value in main = " + ptr.value); // Checkpoint 1
updatePointer(ptr);
System.out.println("Updated pointer value in main = " + ptr.value); // Checkpoint 4
}

private void updatePointer(LinkedList.Node ptr) {
System.out.println("Current pointer value in updatePointer = " + ptr.value); // Checkpoint 2
ptr = ptr.next;
System.out.println("Updated pointer value in updatePointer = " + ptr.value); // Checkpoint 3
}

Before scrolling further, take 30 seconds and predict the outputs at checkpoints 1, 2, 3 and 4. If you’ve been using Java for a while, there’s a decent chance you’ll get three of them right — and still hesitate on the fourth. Your deduction for checkpoint 4 depends entirely on whether you believe Java passes objects by reference.

Java Doesn’t Offer Pass By Reference

Surprise! Java only supports pass-by-value. For primitives, this makes sense. The confusing part is that the value of a reference variable happens to be a reference.

In simple terms — a reference variable stores a reference to an object — not the object itself.¹

That should immediately reveal a problem with the first diagram.

The pointer ptr is not the first node itself. It refers to the first node.

So, a much better way to diagrammatically depict this would be —

Linked List with Nodes (Much better)

Cool. Now let’s understand what happens when pass-by-value is involved with reference variables. This is much better understood through, you guessed it, a diagram.

The Fate of the Pointer

As you can see, when ptr is passed to updatePointer, a copy of the reference stored in ptr (which currently refers to node 1) is passed into updatePointer().

When we reach —

ptr = ptr.next;

Notice what changed: the variable changed — not the node.

The local parameter ptr inside updatePointer() now refers to node 2.

The Update Fate of the Pointer

That’s it. When we are back in main(), the ptr continues to point to node 1. Thus, the output for our little code snippet looks like —

IntelliJ Output With No Formatting

What If I Changed the Underlying Node’s Value

Now take the code snippet below –

void main() {
LinkedList linkedList = new LinkedList();
LinkedList.Node ptr = linkedList.addNode(1);
linkedList.addNode(2);
linkedList.addNode(3);
linkedList.addNode(4);

System.out.println("Current pointer value in main = " + ptr.value); // Checkpoint 1
updatePointer(ptr);
System.out.println("Updated pointer value in main = " + ptr.value); // Checkpoint 4
}

private void updatePointer(LinkedList.Node ptr) {
System.out.println("Current pointer value in updatePointer = " + ptr.value); // Checkpoint 2
ptr.value = 6;
System.out.println("Updated pointer value in updatePointer = " + ptr.value); // Checkpoint 3
}

The output now looks like –

IntelliJ Output (Ran Out of Witty Remarks)

Huh. The underlying value changed. The diagram below shows exactly why.

The Fate of the Value in the Node Being Pointed At

This time, the opposite happened: the node changed — not the variable.

Basically, both copies of ptr still refer to the same node object. Updating that object’s value field is therefore visible from both methods.

Once you distinguish between changing a reference and changing the object it refers to, a surprising number of Java interview questions, linked-list algorithms, and even everyday API behaviour suddenly become much easier to reason about.

¹Most JVM implementations internally represent this as something similar to an address, but the language specification intentionally doesn’t expose that.


The Myth of Pass-by-Reference in Java was originally published in Javarevisited on Medium, where people are continuing the conversation by highlighting and responding to this story.

This post first appeared on Read More