TLDR
In AP Computer Science A, passing an object to a method copies the reference, not the object itself, so the method can change the original object's state through that shared reference. Returning an object also returns the reference, not a fresh copy, which is why careless getters can let outside code modify your private data. The big skill here is tracing what actually changes when references are passed around and avoiding accidental side effects.

How Do Passing and Returning Object References Work?
When a method parameter is an object reference, Java copies the reference value into the parameter. The original variable and the parameter are separate variables, but they can point to the same mutable object. That is why changing the object's fields or elements inside the method can affect the object after the method ends.
Returning an object works the same way: the method returns a reference to an object, not a new independent copy unless the code explicitly creates one. On AP CSA questions, track whether the code changes the object itself, reassigns only a local reference, or exposes private mutable data through a returned reference.
Why This Matters for the AP Computer Science A Exam
This topic is about defining object behaviors through methods that take or return object references and predicting the results of calling those methods. That shows up in two main ways on the AP Computer Science A exam.
On multiple-choice questions, you often trace code that passes arrays, ArrayLists, or other objects into methods and decide whether the original object changed. The trap is treating objects like primitives.
On free-response code writing, especially class design and questions that build or process collections, you write methods that take object references as parameters or return them. You need to handle mutable objects correctly and keep private data protected so your class still encapsulates its state.
Key Takeaways
- Java always passes a copy of what is stored in a variable. For a primitive that is the value; for an object that is the reference.
- A copied reference still points to the same object, so a method can change that object's state, and the change persists after the method returns.
- Reassigning a parameter inside a method (pointing it at a new object) does not affect the original argument's reference.
- Returning an object returns the reference, not a new copy, so a getter can accidentally hand out access to private internal state.
- A method can reach the private data of another object only when that object is the same type as the method's own class.
- Good practice: do not modify mutable objects passed in as parameters unless the specification says to.
Key Concepts
Reference Parameters: Sharing the Key, Not the House
When you pass an object as an argument, Java copies the reference, not the object. Picture copying a house key. Both keys open the same door to the same house. The parameter and the argument point to the same object in memory, so changes made through either reference affect that one shared object.
This is different from primitives. When you pass an int, Java copies the value, and the parameter and argument are independent. With objects, they stay connected through the shared reference.
The rule to hold onto: "pass by value" in Java means copying whatever is in the variable. For primitives that is the value. For objects that is the reference (the way to find the object). Java never passes the object itself.
Modifying Mutable Objects Through Parameters
A mutable object is one whose state can change after it is created. Arrays, ArrayLists, and most custom objects are mutable. When a method receives a reference to a mutable object, it can change that object's state, and those changes stick around after the method returns.
That power comes with responsibility. Good practice says do not modify a parameter object unless that is the method's stated job. A method named calculateAverage should not also sort the array, because that hidden side effect makes code harder to follow and debug.
Sometimes modifying the parameter is the point. A method like sortArray or addStudent is expected to change its parameter, and the method name and documentation should make that clear. When in doubt, leave parameters unchanged or work with a copy.
Returning References: Sharing Access to Internal State
When a method returns an object, it returns the reference, not a new copy. That is efficient because there is no need to duplicate a possibly large object. But it also means the caller now has direct access to what might be your class's internal state, which can break encapsulation.
Think of a getter that returns an ArrayList. If you return your private ArrayList directly, the caller can modify it and possibly break your class. This is a privacy leak: you have exposed internal state that should stay protected.
The fix depends on your goal. Sometimes sharing is intentional and you want the changes reflected. Other times you should return a copy or a read-only view. Be deliberate about whether you are sharing access or handing out independent data.
Access Restrictions Between Types
A subtle but important rule: a method can reach the private members of an object passed as a parameter only when that parameter is the same type as the method's own class. A Student method can read private fields of another Student passed in, but not the private fields of a Teacher.
That makes sense. The Student class knows its own implementation, so it can safely work with other Student instances' internals. It does not know how Teacher is built internally, so those details stay hidden. This rule supports patterns like copy constructors and comparison methods while keeping encapsulation between different classes intact.
Code Examples
Reference passing in action:
</>Java// Example: Understanding reference parameters public class ReferenceDemo { public static void main(String[] args) { // With primitives - no connection after passing int x = 10; changeIntValue(x); System.out.println("x after method: " + x); // Still 10 // With arrays - reference creates connection int[] numbers = {1, 2, 3, 4, 5}; changeArrayValue(numbers); System.out.println("numbers[0] after method: " + numbers[0]); // Now 99! // With objects - same reference behavior Student student = new Student("Alice", 85); changeStudentGrade(student); System.out.println("Grade after method: " + student.getGrade()); // Now 90! } // Primitive parameter - receives copy of value public static void changeIntValue(int num) { num = 99; // Only changes local copy } // Array parameter - receives copy of reference public static void changeArrayValue(int[] arr) { arr[0] = 99; // Changes the actual array } // Object parameter - receives copy of reference public static void changeStudentGrade(Student s) { s.setGrade(90); // Changes the actual student object } } class Student { private String name; private int grade; public Student(String name, int grade) { this.name = name; this.grade = grade; } public int getGrade() { return grade; } public void setGrade(int grade) { this.grade = grade; } }
Privacy leaks and proper encapsulation:
</>Java// Example: Avoiding privacy leaks when returning references public class GradeBook { private ArrayList<Integer> grades; public GradeBook() { grades = new ArrayList<Integer>(); } // BAD: Returns reference to internal list public ArrayList<Integer> getGradesBad() { return grades; // Caller can modify our private list! } // GOOD: Returns copy to protect internal state public ArrayList<Integer> getGradesGood() { return new ArrayList<Integer>(grades); // Safe copy } // ALSO GOOD: Return immutable view public List<Integer> getGradesReadOnly() { return Collections.unmodifiableList(grades); } // Better approach - don't modify the parameter public void addGrades(ArrayList<Integer> newGrades) { for (Integer grade : newGrades) { if (grade >= 0 && grade <= 100) { grades.add(grade); // Only modify our own state } } } }
Access to private members of the same type:
</>Java// Example: Accessing private members of same class type public class BankAccount { private double balance; private String accountNumber; public BankAccount(String accountNumber, double initialBalance) { this.accountNumber = accountNumber; this.balance = initialBalance; } // Can access private members of OTHER BankAccount objects public void transfer(double amount, BankAccount other) { if (amount > 0 && amount <= this.balance) { this.balance -= amount; other.balance += amount; // Direct access to private field! } } // Compare with another account public boolean hasMoreMoney(BankAccount other) { return this.balance > other.balance; // Can read private field } // Copy constructor - common pattern using same-type access public BankAccount(BankAccount other) { this.accountNumber = other.accountNumber + "-COPY"; this.balance = other.balance; // Direct access to private fields } // But can't access private members of different types public void processLoan(LoanAccount loan) { // double loanBalance = loan.balance; // ERROR: Can't access double loanBalance = loan.getBalance(); // Must use public method } } class LoanAccount { private double balance; // Private to LoanAccount public double getBalance() { return balance; } }
Common Errors and Debugging
Unintended Modification of Parameters
Accidentally changing objects passed as parameters:
</>Java// BAD: Method has surprising side effect public static double calculateAverage(ArrayList<Integer> scores) { Collections.sort(scores); // OOPS! Modified the parameter double sum = 0; for (int score : scores) { sum += score; } return sum / scores.size(); } // GOOD: Work with a copy if you need to modify public static double calculateMedian(ArrayList<Integer> scores) { ArrayList<Integer> sorted = new ArrayList<>(scores); // Copy first Collections.sort(sorted); // Sort the copy, not original int middle = sorted.size() / 2; return sorted.get(middle); }
Aliasing Issues
Multiple references to the same object causing confusion:
</>Java// PROBLEM: Two variables reference same list ArrayList<String> list1 = new ArrayList<>(); list1.add("Hello"); ArrayList<String> list2 = list1; // Not a copy! Same list list2.add("World"); System.out.println(list1.size()); // Prints 2 - surprise! // SOLUTION: Make explicit copy when needed ArrayList<String> list3 = new ArrayList<>(list1); // True copy list3.add("!"); System.out.println(list1.size()); // Still 2 System.out.println(list3.size()); // 3
Privacy Leaks Through Getters
Accidentally exposing mutable internal state:
</>Javapublic class Team { private ArrayList<Player> players = new ArrayList<>(); // BAD: Exposes internal list public ArrayList<Player> getPlayers() { return players; // Caller can add/remove players! } } // External code can break invariants: Team team = new Team(); team.getPlayers().clear(); // Removed all players! // GOOD: Return defensive copy public ArrayList<Player> getPlayers() { return new ArrayList<>(players); }
Practice Problems
Problem 1: What does this code print?
</>Javapublic static void main(String[] args) { int[] arr = {1, 2, 3}; mystery(arr); System.out.println(Arrays.toString(arr)); } public static void mystery(int[] a) { a[0] = 99; a = new int[]{7, 8, 9}; a[0] = 77; }
Solution: Prints [99, 2, 3]
a[0] = 99modifies the original array through the referencea = new int[]{7, 8, 9}creates a new array and changes the local reference onlya[0] = 77modifies the new array, not the original
Problem 2: Fix this class to prevent external modification:
</>Javapublic class StudentRecord { private ArrayList<Integer> testScores; public ArrayList<Integer> getTestScores() { return testScores; } }
Solution (any one of these approaches works; you would pick one getter, not all three):
</>Javapublic class StudentRecord { private ArrayList<Integer> testScores; // Option 1: Return a copy public ArrayList<Integer> getTestScores() { return new ArrayList<>(testScores); } // Option 2: Return an unmodifiable view public List<Integer> getTestScoresReadOnly() { return Collections.unmodifiableList(testScores); } // Option 3: Provide specific access methods public int getTestScore(int index) { return testScores.get(index); } public int getTestCount() { return testScores.size(); } }
Problem 3: Write a method that swaps the names of two Student objects. Is this possible?
Solution:
You cannot rely on reassigning the parameter references to swap names, because changing what the local parameters point to does not change the original arguments. But if Student has getName and setName methods, you can swap names by changing each object's state:
</>Javapublic static void swapNames(Student s1, Student s2) { String temp = s1.getName(); s1.setName(s2.getName()); s2.setName(temp); }
This works because s1 and s2 reference the same objects as the arguments, so calling setName changes those actual objects.
How to Use This on the AP Computer Science A Exam
Code Tracing
When a method takes an object parameter, draw the argument and parameter as two arrows pointing at the same object. If the method changes the object's fields or elements, the original changes too. If the method reassigns the parameter to a new object, only the local arrow moves, and the original is untouched.
Free Response
In class design and collection-based code writing, decide intentionally whether a method should change a passed-in object. Unless the specification tells you to modify it, leave mutable parameters alone. For getters that return a reference to private mutable data, return a copy when you need to protect internal state.
Common Trap
Treating object parameters like primitives. With primitives, method changes never affect the original. With objects, changing the object's state through the reference does affect the original. Reassigning the parameter variable, though, never affects the caller's variable.
Common Misconceptions
- "Objects get copied when passed to a method." Only the reference is copied. Both the parameter and the argument point to the same object.
- "Any change inside a method affects the original object." Changing the object's state does, but reassigning the parameter to a new object does not affect the caller.
- "Returning a getter value is always safe." If you return the reference to a private mutable object, the caller can modify your internal state. Return a copy or read-only view when that matters.
- "Primitives and objects behave the same way when passed." Primitive changes never persist; mutable object state changes do.
- "A method can read any object's private fields." It can only reach private members of an object that is the same type as the method's own class.
- "Setting a parameter to null inside a method makes the original null." Reassigning the parameter, including to null, never changes the caller's variable.
Related AP Computer Science A Guides
Vocabulary
The following words are mentioned explicitly in the College Board Course and Exam Description for this topic.Term | Definition |
|---|---|
enclosing class | The class in which a method is defined. |
mutable object | An object whose state can be changed after it is created; when used as a constructor parameter, a copy should be made to prevent external modification. |
object reference | A value that points to the memory location where an object is stored, allowing access to that object. |
parameter | A variable declared in the header of a method or constructor that receives values passed to the method when it is called. |
private data | Class members declared with the private access modifier that can only be accessed within the same class. |
return expression | The value or reference that a method sends back to the code that called it. |
Frequently Asked Questions
What happens when an object is passed to a method in Java?
Java copies the object reference into the parameter. The parameter and argument are separate variables, but they can point to the same object, so changing that object through the parameter can affect the original object.
Are objects copied when passed as parameters?
No. The object itself is not copied. Java copies the reference value, which means both the original variable and the parameter may refer to the same mutable object.
Can a method change an object passed as a parameter?
Yes, if the object is mutable and the method changes its fields or elements through the reference. Reassigning the parameter to a new object, however, only changes the local parameter variable.
What happens when a method returns an object?
When a method returns an object, it returns a reference to that object. It does not automatically create a new copy, so the caller may receive access to the same mutable object.
What is a privacy leak in AP CSA?
A privacy leak happens when outside code gets direct access to private mutable data, such as a getter returning the actual private ArrayList. Returning a copy can protect the class state when sharing is not intended.
How does Topic 3.6 show up on the AP CSA exam?
Topic 3.6 appears in tracing and class-writing questions where you must decide what changes after a method call. Track whether code mutates an object, reassigns a local reference, returns a shared reference, or protects private data.