Pass-by-Value, Always
The Fundamental Rule
Java is always pass-by-value. There are no exceptions.
This is the single most important rule about Java’s memory model and one of the most frequently examined points on the Tripos paper. Misunderstanding it leads to incorrect predictions about program behaviour.
Passing Primitives
When a primitive is passed as an argument, its value is copied into the parameter. The callee cannot affect the caller’s variable:
static void increment(int x) {
x = x + 1;
}
public static void main(String[] args) {
int n = 5;
increment(n);
System.out.println(n); // prints 5, not 6
}
n in main and x in increment are separate variables. x starts as a copy of the value 5, is incremented to 6, and is then discarded when increment returns. n was never touched.
Passing Object References
When an object reference is passed, the reference itself is copied — not the object. Both caller and callee now hold separate copies of the reference, but both copies point at the same single object on the heap.
Mutation Is Visible
If the callee mutates the object through its copy of the reference, the caller sees the change — because there is only one object:
static void mutate(int[] arr) {
arr[0] = 999;
}
public static void main(String[] args) {
int[] data = {1, 2, 3};
mutate(data);
System.out.println(data[0]); // prints 999
}
Both data and arr point at the same array. Modifying through arr modifies that one array.
Reassignment Is NOT Visible
If the callee reassigns its own parameter to point at a different object, the caller is unaffected — the callee only changed its own local copy of the reference:
static void reassign(int[] arr) {
arr = new int[]{4, 5, 6};
arr[0] = 888;
}
public static void main(String[] args) {
int[] data = {1, 2, 3};
reassign(data);
System.out.println(data[0]); // prints 1
}
Step by step:
- Before the call:
datapoints at{1, 2, 3}on the heap. reassignis called:arrreceives a copy ofdata’s reference. Both point at{1, 2, 3}.arr = new int[]{4, 5, 6}:arris now reassigned to point at a new array{4, 5, 6}.datastill points at{1, 2, 3}.arr[0] = 888: modifies the new array{888, 5, 6}.reassignreturns:arris discarded.datastill points at{1, 2, 3}.
THE TRAP: “Java Is Pass-by-Reference for Objects” Is FALSE
A common misconception — and a favourite Tripos trick statement — is: “Java passes primitives by value but objects by reference.”
This statement is wrong. What is actually being passed for objects is a reference by value. The distinction matters:
- Pass-by-reference means the callee receives an alias for the caller’s variable — assigning to the parameter would change the caller’s variable. Java does not do this.
- Pass-by-value of a reference means the callee receives a copy of the reference — it can follow the reference to mutate the object, but it cannot change which object the caller’s variable points to.
If Java were truly pass-by-reference for objects, reassign above would change data in main. It does not.
A useful analogy: writing an address on a slip of paper and handing it to someone. They can use the address to visit the house and rearrange the furniture (mutate). They can also cross out the address on their own slip and write a different address (reassign). Neither action affects the address on your slip. Your slip and their slip are independent copies of the same address.
Wrapper Types Are Immutable
Integer, Double, String, and other wrapper/immutable types cannot be mutated. Combined with pass-by-value, this means you cannot write a method that “changes” an Integer parameter:
static void addOne(Integer x) {
x = x + 1; // auto-unboxing, addition, auto-boxing — creates a NEW Integer
}
public static void main(String[] args) {
Integer n = 5;
addOne(n);
System.out.println(n); // prints 5
}
x = x + 1 creates a new Integer(6) and reassigns x to point at it. The caller’s n still points at Integer(5).
Summary Table
| What is passed | What the callee can do | Visible outside? |
|---|---|---|
| Primitive | Modify the parameter | No (copy) |
| Object reference | Mutate the object | Yes (same object) |
| Object reference | Reassign the parameter | No (copy of reference) |