🧩 Methods · Beginner

Java is always pass-by-value

Primitives copy the value; references copy the reference (object can be mutated, variable cannot be re-pointed).

🧩 The mysteryOne method appends "!" to your StringBuilder, and you see it. Another sets the parameter to a brand-new StringBuilder, and you see... nothing. Same parameter, different fates.

Always a copy

Java has exactly one rule: it always passes a copy of the argument's value (pass-by-value). For a primitive like int, that's a copy of the number, so nothing the method does can reach the caller's variable.

static void bump(int n) {
    n++; // only the copy
}
int n = 5;
bump(n); // n is still 5

Copying a reference

An object variable doesn't hold the object; it holds a reference, like a house address. Passing it copies the address: two addresses, one house. So if the method changes the object (sb.append), the caller sees it.

static void addX(StringBuilder sb) {
    sb.append("X"); // same object
}
var s = new StringBuilder("hi");
addX(s);
// s is now "hiX"
🔮 Predict it

Your turn

What prints?

static void addItem(StringBuilder cart) {
    cart.append("+apple");
}
void main() {
    var c = new StringBuilder("bread");
    addItem(c);
    System.out.println(c);
}
  1. bread
  2. bread+apple
  3. +apple
Show the answer

cart and c are two references to the same StringBuilder. append changes that one object, so main sees bread+apple.

⚠️ The trap

Re-pointing the copy

Assigning a new object to the parameter only changes the method's copy of the reference. The caller's variable still points to the original. Mutating the object is visible; reassigning the parameter never is.

static void addX(StringBuilder sb) {
    sb.append("X");  // caller sees it
    sb = new StringBuilder(); // re-point
    sb.append("Y");  // caller never sees
}
🔮 Predict it

Your turn

What prints?

static void reset(StringBuilder sb) {
    sb = new StringBuilder();
    sb.append("new");
}
void main() {
    var s = new StringBuilder("old");
    reset(s);
    System.out.println(s);
}
  1. new
  2. old
  3. oldnew
Show the answer

old. sb first pointed at the caller's object, then was re-pointed to a fresh one. Only that new object got "new", and it vanished with the method. s still points to the original.

🔮 Predict it

Array vs int

Both values start at 4. What prints?

static void grow(int[] a, int n) {
    a[0] *= 2;
    n *= 2;
}
void main() {
    int[] arr = {4};
    int n = 4;
    grow(arr, n);
    System.out.println(arr[0] + " " + n);
}
  1. 8 8
  2. 4 4
  3. 8 4
  4. 4 8
Show the answer

The array reference is copied, but both copies point to the same array, so a[0] *= 2 is visible. The int n is a plain value copy, so main's n stays 4.

🤔 Think first

Two classic puzzles

Why can't you write swap(int a, int b) that swaps the caller's variables? And why doesn't s = s.toUpperCase(); inside a method change the caller's String?

Think about it, then reveal the answer

Both parameters are copies: swapping or reassigning them leaves the caller alone. And Strings are immutable: toUpperCase() returns a new String, and assigning it only re-points the local copy. The fix in both cases: return the new value (or swap inside an array/object).

💼 In the real world

In real projects

"Is Java pass-by-reference?" is a favorite interview question. The answer: no, Java passes references by value. On the job, methods that mutate objects passed in (like removing items from a caller's list) cause spooky bugs, so many teams pass copies or return new objects instead.

Key takeaways

  1. Primitives: the method gets a copy of the value
  2. Objects: the method gets a copy of the reference
  3. Mutating the object through the copy is visible to the caller
  4. Reassigning the parameter is never visible to the caller

💡 Like handing someone a photocopy of your home address: they can visit and repaint your house, but scribbling a new address on their copy doesn't move your house.

🤯 Did you know?

"Is Java pass-by-reference or pass-by-value?" is one of the most famous questions on Stack Overflow. It was asked back in 2008, and people are still arguing in the comments.

Practice questions

What does this print?

static void change(StringBuilder sb) {
    sb.append("!");
}
void main() {
    var s = new StringBuilder("hi");
    change(s);
    System.out.println(s);
}
  1. hi
  2. !
  3. hi!
  4. Compile error
Check your answer

hi!. sb and s are two references to the same StringBuilder. append changes that one object, so main sees hi!.

What does this print?

static void replace(StringBuilder sb) {
    sb = new StringBuilder("bye");
    sb.append("!");
}
void main() {
    var s = new StringBuilder("hi");
    replace(s);
    System.out.println(s);
}
  1. bye!
  2. hi
  3. hi!
  4. bye
Check your answer

hi. sb starts as a copy of s's reference, then is re-pointed to a new object. Only that new object gets the !, and s still refers to the original "hi".

Next: two methods, one name. How does Java choose which one runs when you call print(5)?