Call by Value and Call by Reference in Java
Is Java pass-by-value or pass-by-reference? The answer is unambiguous: Java is always pass-by-value. The confusion comes from how object references behave β a reference is a value too, and it is that value which gets copied.
Pass-by-value in plain terms
When you pass a variable to a method, Java copies the value of that variable into the method's parameter. Changes to the parameter never affect the caller's variable β only the object the reference points to can be mutated.
Primitives: no surprise
public static void doubleIt(int x) {
x = x * 2;
System.out.println("Inside: " + x);
}
public static void main(String[] args) {
int n = 10;
doubleIt(n);
System.out.println("Outside: " + n);
}
// Inside: 20
// Outside: 10
The parameter x receives a copy of n. Modifying x is local to the method β exactly what "pass by value" means.
Objects: the tricky part
class User {
String name;
User(String name) { this.name = name; }
}
public static void rename(User u) {
u.name = "Bob"; // mutates the shared object
}
public static void replace(User u) {
u = new User("Charlie"); // rebinds the local parameter only
}
public static void main(String[] args) {
User alice = new User("Alice");
rename(alice);
System.out.println(alice.name); // Bob
replace(alice);
System.out.println(alice.name); // Bob (still) β replace had no effect outside
}
What's happening?
aliceholds the value 0x3f21 (a reference to a User object on the heap).- When calling
rename, Java copies that reference into the parameteru. Both variables now point to the same heap object. u.name = "Bob"mutates the object β visible through bothuandalice.u = new User("Charlie")rebinds the localuto a fresh reference.alicenever changes.
If Java were pass-by-reference
This is a quick thought experiment β something Java explicitly does not do:
// Hypothetical pass-by-reference β not legal Java
public static void swap(int& a, int& b) { int t = a; a = b; b = t; }
int x = 1, y = 2;
swap(x, y);
// With real pass-by-reference: x == 2, y == 1
// In actual Java, you cannot swap two ints via a method at all.
C++ and C# (with the ref keyword) support true pass-by-reference. Java does not.
Arrays behave like objects
Arrays are objects in Java, so they follow the same rule as any other reference:
public static void modify(int[] arr) {
arr[0] = 99; // visible outside β mutation through the shared reference
arr = new int[]{1, 2, 3}; // rebind local only β caller sees no change
}
public static void main(String[] args) {
int[] numbers = {10, 20, 30};
modify(numbers);
System.out.println(numbers[0]); // 99
}
Common workarounds
Returning the new value
The cleanest solution β a method that computes a new value should return it:
public static int doubleIt(int x) { return x * 2; }
int n = 10;
n = doubleIt(n); // n == 20
Wrapping in an array or container
When you genuinely need to mutate a primitive argument (rare), wrap it in a one-element array or an AtomicInteger:
public static void increment(int[] holder) { holder[0]++; }
int[] counter = {0};
increment(counter);
System.out.println(counter[0]); // 1
Returning multiple values
Since Java 16, use a record to return structured data without designing a class:
record Stats(int min, int max, double avg) { }
public static Stats analyze(int[] data) {
// compute ...
return new Stats(min, max, avg);
}
Quick reference
| Type passed | Can be reassigned? | Can be mutated? |
|---|---|---|
Primitive (int, boolean, etc.) | No effect outside | N/A |
| Object / Array (reference) | No effect outside | Yes β visible to caller |
String, Integer, other immutables | No effect outside | No (class is immutable) |
Keeping "Java is pass-by-value β even for objects" in mind eliminates the majority of surprises. If a method needs to modify the caller's variable, return a new value; don't try to rebind the parameter.