Question
Is Java Pass-by-Reference or Pass-by-Value? A Clear Beginner Guide
Question
I often hear that Java passes objects by reference, but I also read that Java is strictly pass-by-value. That seems contradictory.
What does Java actually do when values are passed to methods? How do primitive types and object references behave, and why can a method change an object's contents but not replace the caller's variable with a different object?
For example, what is the correct explanation for this distinction in Java?
Short Answer
By the end of this page, you will understand that Java is always pass-by-value. For primitive types, the copied value is the actual number, boolean, or character. For objects, the copied value is the reference to the object, not the object itself. That is why a method can mutate an object through its copied reference, but it cannot reassign the caller's original variable.
Concept
In Java, every method argument is passed by value.
That rule never changes.
The confusion comes from the fact that Java has two broad kinds of values:
- Primitive values like
int,double,boolean, andchar - Reference values that point to objects like
String,ArrayList, or custom class instances
When you pass a primitive to a method, Java copies the primitive value.
int x = 5;
If x is passed to a method, the method receives its own copy of 5.
When you pass an object variable to a method, Java copies the reference value stored in that variable.
Person p = new Person("Ava");
The variable p does not contain the whole object. It contains a reference to the object. When is passed to a method, Java copies that reference.
Mental Model
Think of a variable that stores an object as a piece of paper with an address written on it.
- The object is the house
- The reference is the address written on the paper
- Passing a variable to a method means copying the paper, not moving the house
Now both the caller and the method have separate papers, but both papers contain the same address.
That means:
- If either one goes to the house and paints the door, both will later see the painted door
- If the method writes a new address on its own copied paper, the caller's paper does not change
So:
- Mutating the object works because both references lead to the same object
- Reassigning the parameter does not affect the caller because only the local copy of the reference changes
Syntax and Examples
Core idea
public class Main {
static void changePrimitive(int x) {
x = 99;
}
static void changeObject(Person p) {
p.name = "Liam";
}
static void reassignObject(Person p) {
p = new Person("Mia");
}
public static void main(String[] args) {
int number = 10;
changePrimitive(number);
System.out.println(number); // 10
Person person = new Person("Noah");
changeObject(person);
System.out.println(person.name); // Liam
reassignObject(person);
System.out.println(person.name); // Liam
}
}
class Person {
String name;
Person(String name) {
.name = name;
}
}
Step by Step Execution
Consider this example:
public class Main {
static void update(User user) {
user.name = "Updated";
user = new User("New Object");
user.name = "Changed Again";
}
public static void main(String[] args) {
User u = new User("Original");
update(u);
System.out.println(u.name);
}
}
class User {
String name;
User(String name) {
this.name = name;
}
}
Step-by-step
- In
main,upoints to aUserobject whosenameis"Original". update(u)is called.- Java copies the reference stored in into the parameter .
Real World Use Cases
This concept appears constantly in Java code.
1. Updating objects in service methods
A service method may receive a domain object and update its fields.
void applyDiscount(Product product) {
product.price = product.price * 0.9;
}
The caller sees the updated price because the object itself was mutated.
2. Working with collections
void addDefaultUser(List<String> users) {
users.add("guest");
}
The method changes the same List object the caller passed in.
3. Validation and normalization
void normalize(User user) {
user.name = user.name.trim();
}
This is common when cleaning input before saving data.
4. Reassignments that do not escape the method
void resetList(List<String> items) {
items = new ArrayList<>();
items.add();
}
Real Codebase Usage
In real Java projects, developers use this concept in several common patterns.
Guard clauses before mutation
void updateEmail(User user, String email) {
if (user == null || email == null || email.isBlank()) {
return;
}
user.email = email;
}
The method mutates the object only after validation.
Returning a new object instead of reassigning a parameter
Because reassigning a parameter does not affect the caller, developers often return the replacement.
User upgrade(User user) {
return new User(user.name, "PREMIUM");
}
Usage:
user = upgrade(user);
Mutating collections passed to helper methods
void addAuditEntry(List<String> logs, String message) {
logs.add(message);
}
This is common in data processing and request handling.
Using immutable objects to avoid side effects
Classes like cannot be changed in place.
Common Mistakes
1. Thinking Java changes to a parameter variable affect the caller
Broken assumption:
void setToZero(int x) {
x = 0;
}
Calling this does not change the original variable.
How to avoid it
Return the new value instead:
int setToZero(int x) {
return 0;
}
2. Thinking object reassignment changes the caller's variable
Broken code:
void replacePerson(Person p) {
p = new Person("Emma");
}
This only changes the local parameter.
How to avoid it
Return the new object:
Person replacePerson(Person p) {
return new Person();
}
Comparisons
Java parameter passing compared
| Concept | What gets copied? | Can method mutate shared object? | Can method reassign caller's variable? |
|---|---|---|---|
| Primitive argument in Java | Primitive value | No | No |
| Object argument in Java | Reference value | Yes | No |
| True pass-by-reference | Reference to caller's variable itself | Yes | Yes |
Primitive vs object example
| Case | Example | Effect outside method |
|---|---|---|
| Primitive reassignment | x = 5; | No effect |
Cheat Sheet
Quick rules
- Java is always pass-by-value
- Primitive variables store actual values
- Object variables store references to objects
- Method parameters receive copies of values
- A copied object reference still points to the same object
- Reassigning a parameter does not change the caller's variable
- Mutating an object through a copied reference does affect the shared object
Mini examples
Primitive
void test(int x) {
x = 100;
}
Caller unchanged.
Object mutation
void test(Person p) {
p.name = "Kai";
}
Caller sees changed name.
Object reassignment
void test(Person p) {
p = new Person("Kai");
}
Caller unchanged.
Safe pattern when replacement is needed
FAQ
Is Java pass-by-reference or pass-by-value?
Java is pass-by-value only. For objects, the copied value is the reference.
Why can a Java method change an object if Java is pass-by-value?
Because the method receives a copy of the reference that still points to the same object. Both sides can access that shared object.
Why does reassigning an object parameter not affect the caller?
Because the parameter is only a local copy of the reference. Reassigning it changes that local copy, not the caller's variable.
Are arrays in Java passed by reference?
No. Arrays are objects, so their references are passed by value. A method can change array contents, but it cannot reassign the caller's array variable.
Is String behavior different?
String is still passed by value as a reference, but strings are immutable. Methods cannot change the original String object.
How do I replace an object for the caller in Java?
Return the new object and assign it in the caller.
Does this apply to collections like List and Map?
Yes. A method can mutate the collection contents, but reassigning the parameter will not change the caller's variable.
Mini Project
Description
Build a small Java program that demonstrates the difference between changing an object's fields and reassigning a method parameter. This project helps make Java's pass-by-value behavior visible through printed output.
Goal
Create a program that proves Java passes object references by value, not by reference.
Requirements
- Create a class with at least one mutable field.
- Write one method that mutates the object.
- Write another method that reassigns the parameter to a new object.
- Print values before and after each method call.
- Show clearly which changes are visible in the caller.
Keep learning
Related questions
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Choosing a @NotNull Annotation in Java: Validation vs Static Analysis
Learn how Java @NotNull annotations differ, when to use each one, and how to choose between validation, IDE hints, and static analysis tools.
Convert a Java Stack Trace to a String
Learn how to convert a Java exception stack trace to a string using StringWriter and PrintWriter, with examples and common mistakes.