Primitives vs references: two kinds of luggage

Assignment always copies bits — the question is what those bits mean

Java is strictly pass-by-value. This sentence surprises people, so let's state it precisely: when a method is called, every argument's value is copied into the new frame. For a primitive (int, double, boolean, char…), the value is the bit pattern for the number or character itself. For a reference type, the value is the reference — essentially an address — and not the object it points to. Once you have that sentence right, every "pass by reference" argument in a classroom dissolves.

Concrete picture: int vs StringBuilder

void demo() {
    int count = 10;
    bump(count);
    System.out.println(count);  // still 10

    StringBuilder sb = new StringBuilder("hi");
    appendWorld(sb);
    System.out.println(sb);     // "hi world" — same object, mutated
}

void bump(int x) {
    x = x + 1;                  // only the local copy of count changes
}

void appendWorld(StringBuilder b) {
    b.append(" world");         // follows the reference to the shared heap object
}

count never changes because bump receives a copy of the bits that represent 10 and mutates its own local. sb is a copy of the reference bits — but both the caller and appendWorld now aim at the same StringBuilder instance on the heap, so mutations stick.

What assignment does not do

  • It does not clone objects. Customer a = b; makes a second arrow, not a second customer.
  • It does not copy arrays deeply. int[] copy = original; shares one backing store.
  • == on references compares identity (same heap address), not business equality. Use equals for the latter.

null — a reference with no target

null is a perfectly legal reference value meaning "points at nothing." Dereferencing it throws NullPointerException at the exact bytecode that tried to follow the arrow. Optional<T> and guard clauses exist because humans forget which references might be empty — the machine never forgets.

Open stack / heap story lab →

Takeaways

  • Java is pass-by-value, always. For references, the value is the reference.
  • Assignment copies the slot; it never clones the object or the array.
  • == is identity; equals is equality. Know which you want.
  • null means "no target." Dereferencing it is how NPEs happen.

Enjoying This Lesson?

Your support helps create more comprehensive courses and lessons like this one. Help me build better learning experiences for everyone.

Support Awashyak