3.06 Methods Passing and Returning References of an Object
Pass objects into methods, spot aliasing, and see why changing an object differs from reassigning its reference.
1. LxD Cycle Process
Empathize: Students treat “passing an object” and “passing a copy of the object” as the same thing, so they expect either every change inside a method to vanish when it returns, or every reassignment to somehow reach back into the caller. Both are memory-model misconceptions of exactly the kind found in interviews with early programmers (Kaczmarczyk et al., 2010).
Define:
- POV: CSA students need a reliable way to predict whether a method call changes the caller’s object, because getting this wrong produces bugs that look random – some methods “work” and some silently do nothing, for reasons that feel arbitrary until the reference model clicks.
- Learning Goal: Students will trace what happens to an object reference across a method call and a method return, correctly predicting when a caller’s object is mutated versus left untouched.
Ideate:
- HMW Question: How might we get students to predict a demo’s output before running it, instead of just reading the result after the fact?
- HMW Question: How might we show that mutating through a parameter and reassigning a parameter look almost identical in code but behave completely differently?
- Activity: Predict-then-run two paired demos (mutate vs. reassign), do a hands-on aliasing demo, then apply the same distinction to methods that return references, finishing with two hacks and three debugging-style practice problems.
Prototype & Test: Lesson authors: add what happened in your trial run and what you changed.
2. Lesson Plan
Learning Objective: Trace how object references move into and out of methods, and correctly predict whether a caller’s object is mutated, untouched, or aliased as a result.
Success Criteria: You can predict a demo’s output before running it, explain why using the words “reference,” “mutate,” “reassign,” and “alias,” and write methods that pass and return object references correctly.
Tech Talk (5 minutes)
Java always passes arguments by value – but for an object, the value being copied is a reference, not the object itself.
Shape s = new Shape("square", 4, 4); // s holds a reference, not the object
Shape alias = s; // alias is a second reference to the SAME object
alias.set_width(99); // mutates the one shared object
s.print_shape(); // sees the change -- s and alias are aliases
That one fact explains why mutating a parameter can change the caller’s data, while reassigning it can’t – and it applies the exact same way whether the reference is going into a method as a parameter or coming out of one through return.
From the College Board
AP CSA Unit 5, Topics 5.4 and 5.6. Quoted from the course and exam description (College Board, 2020, pp. 97, 100-101):
- Topic 5.6, “Writing Methods” (Learning Objective MOD-2.F): “When an actual parameter is a reference to an object, the formal parameter is initialized with a copy of that reference, not a copy of the object. If the reference is to a mutable object, the method or constructor can use this reference to alter the state of the object. Passing a reference parameter results in the formal parameter and the actual parameter being aliases. They both refer to the same object.”
- Topic 5.4, “Accessor Methods” (Learning Objective MOD-2.D): “When the return expression is a reference to an object, a copy of that reference is returned, not a copy of the object.”
Oracle’s own language documentation describes the same rule from the language-design side: “Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object’s fields can be changed in the method, if they have the proper access level.” (Oracle, n.d.)
3. Reference Guide
Key Vocabulary
| Term | Definition | Example |
|---|---|---|
| Reference | The address of an object in memory – what a variable actually stores. | Shape s = new Shape(...); – s holds a reference, not the object |
| Pass-by-value | Java copies the value of every argument into the method’s parameter. | Primitives copy the number; objects copy the reference |
| Mutate | Call a method that changes a field on the object a reference points to. | s.set_width(10); |
| Reassign | Point a variable at a completely different object. | s = new Shape(...); |
| Aliasing | Two variables holding the same reference, so both see one shared object. | Shape b = a; |
Mutate vs. Reassign – What the Caller Sees
| Action | On a parameter (object passed in) | On a return value (object passed out) |
|---|---|---|
| Mutate a field through the reference | Caller’s object changes – they share one object | Caller’s object changes – returning a reference doesn’t copy it |
| Reassign the variable to a new object | Caller’s variable is untouched – only the local copy moved | A brand-new object built with new and returned is never an alias of the inputs |
Quick Rule
- Want the caller to see a change → mutate a field with a setter.
- Want a completely independent result → build with
newand return that. - Reassigning a parameter, by itself, never reaches back into the caller.
4. Code Examples
A. Simple: Mutating Through a Parameter
// CODE_RUNNER: Try to predict the output first, then press Run to check.
class Shape {
protected String name;
private int length;
private int width;
public Shape(String name, int length, int width) {
this.name = name;
this.length = length;
this.width = width;
}
public int get_width() { return this.width; }
public void set_width(int w) { this.width = w; }
public void print_shape() {
System.out.println(this.name + ": length=" + this.length + " width=" + this.width);
}
}
public class MutateDemo {
public static void doubleWidth(Shape s) {
s.set_width(s.get_width() * 2);
}
public static void main(String[] args) {
Shape rect = new Shape("rectangle", 10, 5);
rect.print_shape();
doubleWidth(rect);
rect.print_shape();
}
}
B. Complex: Reassigning Does NOT Escape the Method
Reassigning looks almost identical to mutating in code – that’s exactly why it’s the more common bug.
// CODE_RUNNER: Try to predict the output first, then press Run to check.
class Shape {
protected String name;
private int length;
private int width;
public Shape(String name, int length, int width) {
this.name = name;
this.length = length;
this.width = width;
}
public void print_shape() {
System.out.println(this.name + ": length=" + this.length + " width=" + this.width);
}
}
public class ReassignDemo {
public static void replaceShape(Shape s) {
s = new Shape("replacement", 1, 1); // only reassigns the local copy of the reference
}
public static void main(String[] args) {
Shape rect = new Shape("rectangle", 10, 5);
replaceShape(rect);
rect.print_shape();
}
}
[!IMPORTANT] Mutate a field → caller sees it. Reassign the variable → caller doesn’t. Confusing these two is one of the most common bugs when working with objects.
5. Hacks & Practice Tasks
Prepare your submission IPYNB
- Create a new notebook in your portfolio homework area:
_notebooks/homework. - Add one raw cell at the top with the frontmatter:
---
layout: post
codemirror: true
title: Object References HW
categories: [Java]
lesson_language: Java
lesson_topic: Object-References HW
lesson_part: interactive
lesson_type: lesson
permalink: /csa/unit_03/3_6-hw
author: yourGithubID
---
- Add code cells for the Popcorn Hack and the Homework Hack. Make sure every cell runs with visible output.
- Submit the link to your published page at the bottom of this page, and paste this in the description box:
Lesson: CSA 3.6 Methods Passing and Returning References of an Object
MCQ 3.6: <paste the copied result line, such as 3/3 | answers: C,B,C>
Popcorn: growShape mutates length and width, change persists outside the method
Homework: combine returns a brand-new Shape, mutating it does not affect the originals
Submission Safety Rules (Read First)
- One class per cell, ending with a call to its
mainmethod. - Run each cell and leave the output showing.
- Use your own test values where the exercise asks for them.
- Include your MCQ score.
- Use
##headings or smaller.
Popcorn Hack (In-Class)
2-minute challenge: fill in growShape so it mutates the Shape it’s given, then confirm the change persists after the method returns.
// CODE_RUNNER: Fill in growShape so it adds 5 to both length and width, then hit Run to check the output.
class Shape {
protected String name;
private int length, width;
public Shape(String name, int length, int width) { this.name = name; this.length = length; this.width = width; }
public int get_length() { return length; }
public int get_width() { return width; }
public void set_length(int l) { length = l; }
public void set_width(int w) { width = w; }
public void print_shape() { System.out.println(name + ": length=" + length + " width=" + width); }
}
public class Main {
// TODO: add 5 to both s's length and s's width
public static void growShape(Shape s) {
}
public static void main(String[] args) {
Shape rect = new Shape("rectangle", 10, 5);
rect.print_shape();
growShape(rect);
rect.print_shape(); // expect: length=15 width=10
}
}
Aliasing
Because two variables can reference the same object, changes made through one variable are visible through the other.
// CODE_RUNNER: Press Run and see that a and b are aliases of the same Shape -- mutating through b shows up when printing a.
class Shape {
protected String name;
private int length;
private int width;
public Shape(String name, int length, int width) {
this.name = name;
this.length = length;
this.width = width;
}
public void set_width(int w) { this.width = w; }
public void print_shape() {
System.out.println(this.name + ": length=" + this.length + " width=" + this.width);
}
}
public class AliasDemo {
public static void main(String[] args) {
Shape a = new Shape("square", 4, 4);
Shape b = a; // b is now an alias for the same object as a
b.set_width(99);
a.print_shape();
}
}
Returning Object References from Methods
A method can also return a reference to an object. The caller receives a reference to whatever object was returned – it does not create a new copy.
// CODE_RUNNER: Press Run and see that winner is the same object as big -- mutating winner mutates big too.
class Shape {
protected String name;
private int length;
private int width;
public Shape(String name, int length, int width) {
this.name = name;
this.length = length;
this.width = width;
}
public int get_width() { return this.width; }
public void set_width(int w) { this.width = w; }
public double calc_area() {
return this.length * this.width;
}
public void print_shape() {
System.out.println(this.name + ": length=" + this.length + " width=" + this.width);
}
}
public class ReturnRefDemo {
public static Shape biggerShape(Shape s1, Shape s2) {
if (s1.calc_area() >= s2.calc_area()) {
return s1;
}
return s2;
}
public static void main(String[] args) {
Shape small = new Shape("small", 2, 2);
Shape big = new Shape("big", 10, 10);
Shape winner = biggerShape(small, big);
winner.set_width(50);
big.print_shape();
}
}
MCQ Check
3 questions, one at a time. Answer, check, then go to the next one. At the end, copy the score line into your submission notes.
Homework Hack
Task: Fill in combine so it returns a brand-new Shape whose name joins the two inputs’ names, and whose length/width are the sums of each input’s dimensions. Then confirm that mutating the result afterward does not affect either original Shape.
Solution Skeleton:
// CODE_RUNNER: Fill in combine so it returns a brand new Shape combining s1 and s2, then hit Run to check the output.
class Shape {
protected String name;
private int length, width;
public Shape(String name, int length, int width) { this.name = name; this.length = length; this.width = width; }
public String get_name() { return name; }
public int get_length() { return length; }
public int get_width() { return width; }
public void set_width(int w) { width = w; }
public void print_shape() { System.out.println(name + ": length=" + length + " width=" + width); }
}
public class Main {
// TODO: return a brand new Shape joining s1/s2 names with "-", summing length/width
public static Shape combine(Shape s1, Shape s2) {
return null;
}
public static void main(String[] args) {
Shape a = new Shape("square", 4, 4);
Shape b = new Shape("triangle", 3, 3);
Shape result = combine(a, b);
result.print_shape(); // expect: square-triangle: length=7 width=7
result.set_width(999); // mutating result should NOT affect a or b
a.print_shape();
b.print_shape();
}
}
Extra Practice (Optional)
Three more problems that push past the hacks above. Try each one on paper (or in a real editor) before revealing the answer.
Problem 1 - The Swap That Isn’t
A classmate writes this method hoping to swap the names of two Shapes:
public static void swapNames(Shape s1, Shape s2) {
Shape temp = s1;
s1 = s2;
s2 = temp;
}
Shape a = new Shape("square", 4, 4);
Shape b = new Shape("triangle", 3, 3);
swapNames(a, b);
a.print_shape();
b.print_shape();
What actually prints, and why doesn’t the swap work?
Need a hint?
`swapNames` only reassigns its own local copies of the references (`s1` and `s2`). None of those three assignments ever calls a setter on the actual objects `a` and `b` refer to, so the caller's variables never change. It still prints `square` for `a` and `triangle` for `b` - completely unswapped. To really swap the data, you'd need to mutate fields (e.g. swap `name` through a `set_name` setter), not reassign the parameters.Problem 2 – Reference Equality vs. Value Equality
Write a method isSameShape(Shape s1, Shape s2) that returns true only when s1 and s2 are aliases of the exact same object (not just two objects with equal dimensions). Then test it against three cases: the same reference, two different objects with identical length/width, and two different objects with different dimensions.
// CODE_RUNNER: Fill in isSameShape so it only returns true when both parameters are aliases of the exact same object, then hit Run to check all three test cases.
class Shape {
protected String name;
private int length;
private int width;
public Shape(String name, int length, int width) {
this.name = name;
this.length = length;
this.width = width;
}
public int get_length() { return this.length; }
public int get_width() { return this.width; }
}
public class Main {
// TODO: return true only when s1 and s2 are aliases of the exact same object
public static boolean isSameShape(Shape s1, Shape s2) {
return false;
}
public static void main(String[] args) {
Shape a = new Shape("square", 4, 4);
Shape b = a;
Shape c = new Shape("square", 4, 4);
Shape d = new Shape("triangle", 3, 3);
System.out.println("a and b (same object): " + isSameShape(a, b));
System.out.println("a and c (equal dimensions, different object): " + isSameShape(a, c));
System.out.println("a and d (different object, different dimensions): " + isSameShape(a, d));
// Expected output:
// a and b (same object): true
// a and c (equal dimensions, different object): false
// a and d (different object, different dimensions): false
}
}
Problem 3 - Find and Fix the Bug
This method is supposed to reset a Shape back to a 1×1 square, but callers report the original object never changes:
public static void resetShape(Shape s) {
s = new Shape("square", 1, 1);
}
Fix it so the caller’s object is actually reset.
Need a hint?
The bug is the same reassignment pitfall from Problem 1 - `s = new Shape(...)` only repoints the local variable `s`, it never touches the object the caller passed in. The fix is to mutate the existing object's fields instead: `s.set_name("square"); s.set_length(1); s.set_width(1);`.6. Grading Plan (1 Point Total) – proposed, adjust as needed
| Part | Points | What earns the points |
|---|---|---|
Popcorn (growShape) |
0.2 | Mutates both length and width through setters, and the change persists after the method returns. |
| MCQ | 0.2 | 3/3 correct. 0.15 for 2/3, 0.1 if every question was answered. |
Homework: combine builds new object |
0.2 | Uses new Shape(...) rather than returning either input. |
| Homework: name/dimensions correct | 0.2 | Name joins both inputs; length/width are the correct sums. |
| Homework: mutation isolation verified | 0.2 | Prints a and b after mutating the result to show they’re unaffected. |
| Total | 1.0 |
Quick Validation Checklist
- Each cell runs and shows output.
- MCQ score in the submission notes.
growShapemutates the existing object (nonew Shapeinside it).combinereturns anew Shape, nevers1ors2directly.
7. Lesson Revisions & Feedback Evidence
Feedback Received: Lesson authors: what your peers said in the practice run.
Revision Made: Lesson authors: what you changed because of it.
References
College Board. (2020). AP Computer Science A course and exam description (Unit 5: Writing Classes, Topics 5.4 & 5.6, pp. 97, 100–101). https://apcentral.collegeboard.org/media/pdf/ap-computer-science-a-course-and-exam-description.pdf
Oracle. (n.d.). Passing reference data type arguments. The Java Tutorials. Oracle Corporation. Retrieved September 17, 2026, from https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
Submit Assignment
Need to update a submission later? Open the submissions dashboard.