Pass By Reference And Pass By Value In Java

8 min read

Pass by Value and Pass by Reference in Java: Understanding How Java Handles Method Arguments

When developers talk about method parameters in Java, the terms pass by value and pass by reference often surface. Day to day, although Java officially uses pass by value for all method arguments, the behavior can sometimes look like pass by reference, especially with objects and arrays. Grasping these concepts is crucial for writing predictable code, avoiding subtle bugs, and mastering Java’s memory model. This article breaks down what pass by value means, why Java does not support true pass by reference, and how object references create the illusion of reference semantics.

Introduction

Java’s parameter passing mechanism is based on pass by value, a principle that applies uniformly to primitive types and object references alike. Think about it: in practice, this means that when you invoke a method, the JVM creates a local copy of the value (or the reference’s address) and passes that copy to the method. The original variable outside the method remains unchanged for primitives, while object fields can be modified because the reference points to the same object in memory. Understanding this distinction helps you reason about mutability, thread safety, and the design of APIs Worth keeping that in mind..

Value Types vs. Reference Types

Primitive Types (Pass by Value)

Primitive types in Java include byte, short, int, long, float, double, char, and boolean. These are stored directly in the stack, and each variable holds its own data. When you pass a primitive to a method, Java copies the actual value It's one of those things that adds up..

void increment(int x) {
    x++; // modifies the local copy, not the original
}
int a = 5;
increment(a); // a remains 5

Because the copy is independent, changes inside the method do not affect the caller’s variable. This is the textbook example of pass by value.

Object Types (References)

Object types (like String, ArrayList, or any user‑defined class) are stored on the heap, while the variable itself holds a reference (a pointer) to that object. When you pass an object reference to a method, Java copies the reference value, not the object itself. Both the caller and the method now refer to the same object.

class Data {
    int value;
}

void modify(Data d) {
    d.value = 99; // modifies the object referenced by d
}
Data obj = new Data();
obj.value = 10;
modify(obj); // obj.

The reference is copied, so both variables point to the same `Data` instance. This behavior often leads to the misconception that Java uses pass by reference for objects, but it is still **pass by value**—the value being the reference address.

## Pass by Value in Java: Detailed Look

### How the JVM Implements Pass by Value

When a method is called, the JVM performs the following steps:

1. **Evaluate the argument expressions** – The arguments are computed in the caller’s context.
2. **Create a new stack frame** – A local variable for each parameter is allocated in the callee’s stack frame.
3. **Copy the values** – For primitives, the actual data is copied. For objects, the reference (memory address) is copied.
4. **Execute the method body** – The method works with its local copies.
5. **Return (if applicable)** – Any primitive return value is copied back; object references are simply returned as copies of references.

Because the original data is never exposed directly, the caller’s variables remain untouched for primitives, while object state can change through the shared reference.

### Practical Implications

- **Immutable objects** like `String` or `Integer` cannot be altered after creation, so passing them is effectively read‑only.
- **Mutable objects** such as custom classes or collections can be modified because the method receives a reference to the same instance.
- **Performance**: Passing primitives is cheap; passing object references incurs minimal overhead because only a reference is copied.

## Pass by Reference in Java: The Myth

Java does **not** provide true pass by reference. There is no language construct that allows you to pass a variable by its memory address and have the callee modify the original variable directly. The closest you can get is by wrapping the variable in a mutable container (e.g., an array of size one, a custom wrapper class, or a `AtomicReference`). These containers are still passed by value, but because they hold a reference to the original data, the data can be changed indirectly.

### Example of Simulated Pass by Reference

```java
void swap(int[] a, int[] b) {
    int temp = a[0];
    a[0] = b[0];
    b[0] = temp;
}
int[] x = {1};
int[] y = {2};
swap(x, y); // x[0] is now 2, y[0] is now 1

Here, x and y are references to two separate array objects. The method swaps the contents of those objects, giving the appearance of pass by reference, but the references themselves are still passed by value Worth keeping that in mind..

Method Arguments: Common Scenarios

Arrays and Multi‑Dimensional Arrays

Arrays in Java are objects. When you pass an array to a method, you are passing a reference to the array’s internal storage. The method can read, write, or even replace the elements, but it cannot change the reference in the caller’s scope Most people skip this — try not to..

void fillArray(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
        arr[i] = i * i;
    }
}
int[] numbers = new int[5];
fillArray(numbers);

All elements of numbers become squares after the call That's the part that actually makes a difference..

Wrapper Classes and Immutable Objects

Wrapper classes (Integer, Double, etc.Day to day, ) are immutable. Passing them to a method does not allow modification of the original value because any operation returns a new instance.

void addOne(Integer n) {
    // n = n + 1; // This reassigns the local reference, not the original
}
Integer a = 5;
addOne(a); // a is still 5

Collections and Maps

Collections like List, Set, and Map are also objects. Passing a List reference enables the method to add, remove, or clear elements, but it cannot replace

the original reference in the caller’s scope. If the method assigns a brand‑new collection to its parameter, only the local variable changes; the caller’s variable still points to the initial object.

void replaceList(List list) {
    list = new ArrayList<>(); // reassignment affects only the local parameter
    list.add("replacement");
}
List names = new ArrayList<>();
names.add("original");
replaceList(names);
// names still contains ["original"]

Returning Values Instead of Mutating Arguments

Because Java cannot modify the caller’s variable directly, the idiomatic way to update a value is to return the result and let the caller reassign it.

int increment(int value) {
    return value + 1;
}
int score = 10;
score = increment(score); // score is now 11

For objects, returning a new instance or modifying the existing mutable object in place are both valid patterns, but the choice should be explicit in the method’s contract Most people skip this — try not to..

Summary of Key Points

  • All method arguments in Java are passed by value.
  • For primitives, the value is a copy of the data.
  • For objects, the value is

For objects, the value is a copy of the reference, so the method works with the same underlying object unless it reassigns the parameter to a new instance.

When the method mutates the object’s fields, the caller observes those changes because both the original variable and the parameter point to the identical instance. This behavior is why side‑effects are possible, but it also means that the method’s contract should be explicit about whether it will modify its arguments in place or merely return a new object.

A common pattern is to keep methods pure — i., they read the argument but never alter its state. e.Pure methods make reasoning about code easier and reduce the risk of subtle bugs, especially in multithreaded environments where shared mutable state can lead to race conditions. If mutation is required, document it clearly and consider returning the modified object or a new instance so the caller can decide whether to adopt the change The details matter here..

Another nuance arises with arrays. An array itself is an object, so passing it to a method gives the method a copy of the reference. The method can change the contents of the array — setting elements, swapping values, or even replacing the entire array reference — but the caller’s variable will only see the latter effect if the method reassigns the parameter. Reassigning inside the method does not affect the original reference; it merely changes the local copy Less friction, more output..

This is the bit that actually matters in practice.

To illustrate, consider a method that attempts to replace a list:

void reset(List list) {
    list = Collections.emptyList(); // only the local reference changes
    list.add(42);
}
List data = new ArrayList<>(List.of(1, 2, 3));
reset(data);
// data still contains [1, 2, 3]

The reassignment creates a new list object, but the original data variable continues to reference the initial list. Think about it: by contrast, modifying the existing list — such as calling list. clear() — affects the caller because both references point to the same mutable object.

Best practices for method arguments in Java therefore include:

  1. Prefer immutable arguments when possible. Passing a String, a BigDecimal, or a custom immutable class eliminates the need for the caller to worry about unintended mutations.
  2. Document mutability. If a method will change the contents of a collection, state this explicitly in its Javadoc so callers are aware of the side‑effect.
  3. Return new objects when the result is conceptually a different value. This avoids hidden state changes and aligns with functional‑style thinking.
  4. Limit the scope of mutations. Keep the mutable region as small as possible, and consider extracting the mutating logic into a separate helper method to improve readability.

To keep it short, Java’s argument passing model delivers a copy of the reference for objects, allowing the method to interact with the underlying object but not to replace the caller’s variable directly. Understanding this distinction helps developers write clearer, safer code, and guides the choice between in‑place modification and returning new instances.

Just Shared

Freshly Published

Fits Well With This

Also Worth Your Time

Thank you for reading about Pass By Reference And Pass By Value In Java. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home