AP COMPUTER SCIENCE A • CLASS CREATION

Methods: Passing and Returning References of an Object

Understand how Java methods share and return object references, and why aliasing shapes every program you write.

Historical Context & Motivation

From the earliest days of programming, language designers wrestled with a fundamental question: when a function receives data, does it get a fresh copy, or does it operate on the original? The answer determines whether side effects propagate across a program and whether large data structures can be shared efficiently. Java's designers chose a model rooted in decades of language evolution—one that treats primitive values and object references very differently when they are passed into or returned from methods.

1960s
Pass-by-Reference in FORTRAN & ALGOL
Early languages like FORTRAN used pass-by-reference, allowing subroutines to modify caller variables directly. ALGOL 60 introduced pass-by-name and pass-by-value, sparking debate about parameter semantics.
1972
C's Pass-by-Value with Pointers
C adopted strict pass-by-value but allowed programmers to pass pointer values, simulating reference semantics. This made the distinction between a value and a reference explicit in syntax.
1980s
Smalltalk & Object References
Smalltalk popularized the idea that variables hold references to objects on the heap, not the objects themselves. Passing a variable meant copying the reference—not the object.
1995
Java Codifies Pass-by-Value of References
Java inherited Smalltalk's heap model but used C-family syntax. The JLS specifies that all arguments are passed by value; for objects, the value being copied is the reference itself.

The question this lesson addresses is deceptively simple: when you pass an object to a method in Java, or return an object from one, what exactly is transmitted? Understanding the answer—a copy of the reference, not a copy of the object—is the key to reasoning about aliasing, mutation, and encapsulation in every AP Computer Science A program.

Core Principles & Definitions

Before diving into code, it is essential to internalize several foundational ideas that govern how Java manages memory and parameter passing. Each principle below appears repeatedly on the AP exam, and confusing any one of them is a common source of errors.

1

Reference vs. Object

A reference is a variable that stores the memory address of an object on the heap. It is not the object itself. Multiple references can point to the same object, creating aliases.
2

Pass-by-Value (Always)

Java always copies the value of a variable into the parameter. For primitives, the actual number is copied. For objects, the reference (address) is copied—so caller and method share the same object.
3

Mutation Through a Reference

Because both the caller's variable and the method's parameter point to the same object, calling a mutator method (setter) through either reference changes the one shared object.
4

Reassignment ≠ Mutation

Reassigning the parameter inside a method (e.g., param = new Dog()) only changes the local copy of the reference. The caller's variable still points to the original object.
5

Returning a Reference

A method with a return type of a class returns a copy of a reference. The caller can then store it, creating a new alias, or chain method calls on the returned object.
KEY TAKEAWAY
KEY TAKEAWAY

Visual Explanation — Memory Model

The following diagram illustrates what happens in memory when a reference is passed to a method. Focus on how the stack frames for main and grow both contain arrow-shaped references that point to the same Dog object on the heap.

The cyan arrow from main() and the violet arrow from grow(d) both terminate at the same Dog object on the heap. Calling d.setAge(5) mutates the shared object, so after grow returns, myDog.getAge() also yields 5.

Notice the critical distinction: both stack variables store the same hex address (0x3A7). They are independent copies of that address, but they point to the same location. If grow were to execute d = new Dog("Fido", 1), only the local variable d would change; myDog in main() would remain untouched.

How It Works — Pass-by-Value of References in Detail

Passing a Reference as an Argument

When you write someMethod(myObj), Java evaluates myObj to obtain the reference value (the address of the object on the heap), then copies that value into the formal parameter declared in the method signature. This copy is a new variable living in the called method's stack frame. Because both variables now hold the same address, any state-changing call through either reference modifies the same object. However, reassigning the parameter inside the method has no effect on the caller's reference—the copy simply starts pointing elsewhere.

Returning a Reference from a Method

A return statement in a method whose return type is a class copies the reference value back to the caller's context. The caller can store this in a variable, thereby creating a new alias to the object. This mechanism is fundamental when writing accessor (getter) methods that return instance variables of a reference type. If the returned object is mutable, the caller can use the returned reference to modify private state—a classic encapsulation leak that appears frequently on the AP exam.

AP EXAM TIP

Code Walkthrough — Passing vs. Reassigning

Consider the following class and driver:

public class Point { private int x; private int y; public Point(int x, int y) { this.x = x; this.y = y; } public void translate(int dx, int dy) { x += dx; y += dy; } public String toString() { return "(" + x + ", " + y + ")"; } }

public class Demo { public static void shift(Point p) { p.translate(1, 1); // mutates the shared object p = new Point(0, 0); // reassigns local copy only } public static void main(String[] args) { Point pt = new Point(3, 4); shift(pt); System.out.println(pt); // prints (4, 5) } }

After shift(pt) is called, the parameter p is a copy of pt's reference. The translate call mutates the shared Point to (4, 5). The subsequent p = new Point(0, 0) redirects only the local p; pt in main still points to the mutated Point (4, 5).

Detailed Breakdown — Aliasing Scenarios

The interplay between passing references, returning references, and storing them creates several distinct aliasing scenarios. Recognizing these patterns quickly is crucial for tracing code on the AP exam.

Three aliasing scenarios compared. Scenario ① (pass + mutate) affects the caller because both references share the same object. Scenario ② (pass + reassign) has no effect on the caller. Scenario ③ (return a reference) gives the caller a new alias to a newly created or existing object.
Common reference-passing scenarios on the AP exam
ScenarioInside MethodCaller After Call
Pass + Mutated.setAge(5);Sees updated age (5)
Pass + Reassignd = new Dog("Bo");Original object unchanged
Return Referencereturn new Dog("Lu");Caller stores new alias
Return field referencereturn this.myList;Caller can mutate private field—encapsulation risk

Worked Example

Consider the following complete program. Trace through it step by step to predict the final output.

public class BankAccount { private double balance; public BankAccount(double b) { balance = b; } public void deposit(double amt) { balance += amt; } public double getBalance() { return balance; } public String toString() { return "$" + balance; } } public class Bank { public static BankAccount openAndDeposit(BankAccount acct, double amt) { acct.deposit(amt); BankAccount bonus = new BankAccount(50.0); acct = bonus; // reassign local parameter return bonus; } public static void main(String[] args) { BankAccount mine = new BankAccount(100.0); BankAccount gift = openAndDeposit(mine, 25.0); System.out.println(mine); // ? System.out.println(gift); // ? } }

1
Step 1 — Identify the objects at the call siteIn main, mine references a BankAccount with balance 100.0. A copy of that reference is passed to acct in openAndDeposit.
acct → BankAccount(100.0) (same object as mine)
2
Step 2 — Mutation through acctacct.deposit(25.0) is called. Since acct and mine alias the same object, the balance of that shared BankAccount becomes 125.0.
Shared object balance = 125.0
3
Step 3 — New object createdBankAccount bonus = new BankAccount(50.0) allocates a brand-new object on the heap. bonus is a local variable pointing to this new object.
bonus → BankAccount(50.0)
4
Step 4 — Parameter reassignment (no effect on caller)acct = bonus makes the local parameter acct point to the bonus account. This does NOT change mine in main, which still references the original BankAccount (now with balance 125.0).
mine still → BankAccount(125.0)
5
Step 5 — Return and final outputreturn bonus sends a copy of the reference to the 50.0-balance account back to main, where it is stored in gift. The println statements output:
mine → $125.0, gift → $50.0

Common Pitfalls & Comparisons

Students frequently confuse pass-by-value of a reference with true pass-by-reference (which Java does not support). The table below contrasts common misconceptions with correct reasoning.

Common misconceptions about Java parameter passing
MisconceptionRealityWhy It Matters
"Java passes objects by reference."Java passes the reference by value—a copy of the pointer, not the object.Reassigning a parameter inside a method cannot change the caller's variable.
"Returning an object creates a new copy."Returning copies the reference, not the object. Two variables now alias the same object.If the object is mutable, the caller can change its state through the returned reference.
"A getter that returns a private object is safe."Returning a mutable private field exposes it. The caller can modify internal state.This is a privacy leak. Use defensive copying or return immutable views.
"Primitives and objects are passed the same way."Both are pass-by-value, but the effect differs because one copies a number, the other copies an address.Mutating an object parameter affects the caller; changing an int parameter does not.
KEY TAKEAWAY
KEY TAKEAWAY

Connection to Advanced Topics

The mechanics of passing and returning references underpin several more advanced concepts that extend beyond the AP curriculum but are crucial for college computer science. Understanding these connections now will deepen your reasoning.

AP concepts vs. advanced extensions
AP-Level ConceptAdvanced Extension
Aliasing through parameter passingConcurrency hazards: two threads with aliases to the same object can create race conditions.
Returning a private mutable fieldDefensive copying and immutable collections (e.g., Collections.unmodifiableList) to enforce encapsulation.
Pass-by-value of referencesIn languages like C++, true pass-by-reference (using &) allows a function to reassign the caller's variable.
Garbage collection after references go out of scopeManual memory management in C/C++, weak references, and reference counting in Python.

On the AP exam, you will not be asked about concurrency or defensive copying explicitly. However, questions about encapsulation often test whether you understand that returning a reference to a mutable private field allows external code to violate the class's invariants. Recognizing this pattern quickly is a hallmark of strong exam performance.

Practice Problems

1
Consider the following method: public static void mystery(String s) { s = s + " world"; } If the caller executes String msg = "hello"; mystery(msg);, what is the value of msg after the call? A) "hello world" B) "hello" C) "world" D) null
2
Consider the following code: public class Num { private int val; public Num(int v) { val = v; } public void add(int n) { val += n; } public int getVal() { return val; } } public static void bump(Num x) { x.add(10); } Num a = new Num(5); bump(a); System.out.println(a.getVal()); What is printed? A) 5 B) 10 C) 15 D) 0
3
Consider the following code: public class Box { private int size; public Box(int s) { size = s; } public void grow(int n) { size += n; } public int getSize() { return size; } } public static Box resize(Box b) { b.grow(3); b = new Box(100); b.grow(5); return b; } Box x = new Box(10); Box y = resize(x); System.out.println(x.getSize() + " " + y.getSize()); What is printed? A) 10 105 B) 13 105 C) 100 105 D) 13 100
PROBLEM 4APPLIED
A student is designing a Roster class that stores an ArrayList<Student> as a private instance variable. The class includes the following accessor: public ArrayList<Student> getStudents() { return students; } Part (a): Explain why this accessor creates an encapsulation problem. Part (b): Write a corrected version of getStudents that prevents the caller from modifying the internal list. Part (c): Suppose a caller writes roster.getStudents().add(new Student("Eve")); using the original (buggy) accessor. Describe what happens to the Roster object's internal state. Part (d): If Student is a mutable class, explain why even a defensive copy of the list might not fully protect encapsulation.
PROBLEM 5CRITICAL THINKING
Consider a method swap intended to exchange the objects that two reference variables point to: public static void swap(Dog a, Dog b) { Dog temp = a; a = b; b = temp; } Part (a): Explain why calling swap(d1, d2) from main does NOT actually swap d1 and d2. Part (b): Describe a design pattern or wrapper approach that would allow the caller to achieve the effect of swapping using Java's pass-by-value semantics. Part (c): Explain how this limitation relates to the broader principle that Java is strictly pass-by-value.
Varsity Tutors • AP Computer Science A • Methods: Passing and Returning References of an Object