The Stacks
UNIT 3: CLASS CREATION · TOPIC 3.6

3.6 Methods: Passing and Returning References of an Object

When you pass an object to a method, you pass its address. The method can change the object — and the caller sees it. Primitives don't work that way.

What you need to know

  • Java passes all arguments by value. For primitives, the value is the number. For objects, the value is the reference — so the parameter and the argument point to the same object.
  • A method can modify the object a reference parameter points to (call its mutators, change array elements), and the caller sees the change.
  • A method cannot make the caller's variable point to a different object. Reassigning the parameter (p = new Thing()) only changes the local copy of the reference.
  • Changing a primitive parameter never affects the caller.
  • Returning an object returns its reference. The caller can then modify that object through the returned reference.
  • Returning a reference to a private instance variable that is a mutable object breaks encapsulation — outside code can change internal state. Strings are safe because they're immutable.

Worked example

public static void bump(Counter c, int n)
{
    c.increment();      // affects the caller's object
    n++;                // affects only the local n
    c = new Counter("other");   // caller's variable still points to original
    c.increment();      // this increments the new local object only
}

Counter myC = new Counter("a");   // count 0
int myN = 5;
bump(myC, myN);
System.out.println(myC.getCount());   // 1
System.out.println(myN);              // 5
Exam tip: Draw the arrow. Parameter and argument arrows point to the same box; mutating the box is visible to both. Reassigning the parameter moves only the parameter's arrow. Primitives are just copied numbers.

Going deeper

The nuance, edge cases, and connections that turn a 3 into a 5.

  • Java is always pass-by-value. The value of a reference variable is an address. So passing an object passes a copy of the address — the parameter points to the same object. The phrase "pass by reference" is misleading in Java; it's pass-by-value where the value is a reference.
  • Consequence 1: a method can call mutators on a parameter object and the caller sees the changes. void bump(Counter c) { c.increment(); } — the caller's Counter is incremented.
  • Consequence 2: a method cannot replace the caller's object. c = new Counter(); inside the method just repoints the local parameter. The caller's variable still points to the original.
  • Arrays are objects, so passing an array lets the method modify its elements (arr[0] = 5 is visible to the caller) but not replace the array (arr = new int[10] is not). This is the basis for many Unit 4 questions.
  • Strings are objects but immutable, so a method receiving a String can't change it — every String method makes a new String, and reassigning the parameter doesn't affect the caller. Strings behave like primitives for practical purposes.
  • Returning a reference gives the caller access to the object. If a class returns a reference to its private mutable field (an ArrayList, say), the caller can modify the object's internals — an encapsulation leak. Returning a String or primitive is safe. FRQ 2 sometimes asks you to return a copy for this reason.
  • Draw it. Boxes for objects, arrows for every variable and parameter. Mutation = change inside a box (visible everywhere). Reassignment = move one arrow (visible only there).

Mistakes that cost points

  • Expecting reassignment to propagate. param = new Thing() changes only the parameter.
  • Expecting a primitive parameter to change the caller. Never.
  • Thinking a String parameter can be modified. Immutable. Reassigning it locally does nothing to the caller.
  • Forgetting that array elements are shared. Modifying arr[i] in a method changes the caller's array.

Practice questions

Written in the style of the real exam. Try each one before revealing the answer.

Q1 Consider the following method, where Score has a mutator add(int p) and accessor getPoints().
public static void update(Score s, int pts)
{
    s.add(pts);
    pts = 0;
}
After Score sc = new Score(); int p = 10; update(sc, p);, what are sc.getPoints() and p?
  1. A 0 and 0
  2. B 10 and 10
  3. C 10 and 0
  4. D 0 and 10
Show answer

Answer: B. s and sc share the object, so add(10) is visible: 10 points. pts is a local copy; setting it to 0 doesn't change p.

Q2 Consider the following.
public static void reset(Counter c)
{
    c = new Counter("new");
}
Counter x = new Counter("old");
x.increment();
reset(x);
System.out.println(x.getCount());
What is printed?
  1. A 0
  2. B 1
  3. C null
  4. D A compile-time error
Show answer

Answer: B. reset only reassigns its local parameter. x still points to the original object with count 1.

Key vocabulary

Pass by value
Java copies the argument's value; for objects that value is a reference
Reference parameter
a parameter that holds the address of the caller's object