đź§ Can You Spot the Bug?
Let’s play a quick game. Here's a simple Java method that attempts to reverse a singly linked list. Looks legit, right?
private static void reverseList(Node root) {
Node p1 = root;
Node p2 = root;
while (p2 != null) {
if (p1 == p2) {
p2 = p1.next;
p1.next = null;
} else {
Node t = p2.next;
p2.next = p1;
p1 = p2;
p2 = t;
}
}
root = p1; // update the head
}
Now let’s say you use it like this:
Node head = ... // some linked list
reverseList(head);
System.out.println(head); // still pointing to original head?
You expected the list to be reversed. But surprise! It’s not.
âť“ What's Going On?
Take a moment. Can you figure out why this doesn't work?
It looks like the method updates root
to point to the new head (p1
). So why does the original head
variable remain unchanged outside the method?
Let’s break it down.
đź§Ş Java Passes Object References By Value
Here’s the core idea you need to remember:
In Java, object references are passed by value.
That means: when you pass an object to a method, you’re passing a copy of the reference, not the actual reference itself.
So when you do:
private static void reverseList(Node root) {
...
root = p1; // this only updates the local copy
}
You're just changing the copy of the reference inside the method. The original head
in the caller? Totally untouched.
Think of it like this:
- You handed Java a sticky note that says “Node A lives here.”
- Java made a photocopy of that sticky note.
- Inside the method, you scribbled “Now point to Node Z” on your copy.
- But the original sticky note (outside the method) still says “Node A.”
🔄 So How Do You Actually Reverse the List?
This is the cleanest and most common solution.
private static Node reverseList(Node root) {
Node prev = null;
Node current = root;
while (current != null) {
Node next = current.next;
current.next = prev;
prev = current;
current = next;
}
return prev;
}
Then just call it like this:
head = reverseList(head); // easy and readable
đź§ Takeaway: Understanding Reference Passing in Java
Let’s put it simply:
- Java always passes function arguments by value.
- When you pass an object, what you're really passing is a copy of the reference.
- If you reassign the parameter inside the method, it doesn’t affect the original reference.
- If you modify the contents of the object, that does affect the original — because both the original and the copy point to the same object.
TL;DR
void changeString(String s) {
s = "new"; // does nothing outside the method
}
void changeList(List<String> list) {
list.add("hello"); // modifies the original list
}
So be cautious when you're passing objects around and expecting changes to "stick" — reassigning the reference doesn't cut it.
👋 Hope this helped clarify a common Java gotcha! Let me know if you’ve fallen into this trap before — we all have at some point.
Member discussion