Pass-by-value: the most-misunderstood Java rule
Java is always pass-by-value — even for objects. What that means precisely.
Java is always pass-by-value
When you call a method, the value of each argument is copied into the parameter. For primitives, that's the numeric value. For objects, that's the reference (memory address) — not the object itself.
Primitive — the caller's variable is unaffected:
static void doubleIt(int n) { n = n * 2; }
int x = 5;
doubleIt(x);
System.out.println(x); // 5 — unchanged; doubleIt got a copy
Reference — the object is shared, but reassigning the parameter doesn't affect the caller:
static void clear(StringBuilder sb) {
sb.setLength(0); // mutates the shared object — CALLER SEES THIS
}
static void replace(StringBuilder sb) {
sb = new StringBuilder("new"); // reassigns the local copy — CALLER DOES NOT see this
}
StringBuilder buf = new StringBuilder("hello");
clear(buf);
System.out.println(buf); // "" — mutation is visible
buf = new StringBuilder("hello");
replace(buf);
System.out.println(buf); // "hello" — reassignment not visible
The key insight: mutating the object through the reference propagates (caller and method share the same object), but reassigning the parameter variable only changes the local copy — the caller's reference is untouched.