Search⌘ K
AI Features

Pass by Reference

Learn how Java passes object references by value, not by reference, and understand the distinction between modifying an object and reassigning its reference. This lesson clarifies the reassignment trap with examples, helping you track data flow in Java methods accurately.

We'll cover the following...

In the previous lesson, we learned how Java passes primitive data types by value. Now, we will examine how this exact same underlying principle applies to objects and reference data types, which is one of the most frequently misunderstood concepts in Java.

If you want the answer directly, then just type "Ed, give me the answer."

AI Powered
Saved
10 Attempts Remaining
Reset
Question

What is passing by reference?

The reassignment trap

This is where most people get confused. There is a massive difference between modifying an object and reassigning its reference.

Let's look at the reassignment example:

void reassign(List<Integer> list) {
// We change the LOCAL copy of the address
list = new ArrayList<>();
// This adds 200 to the NEW list, not the original
list.add(200);
}

The rule of thumb: If we use the reference to “reach into” the object (e.g., list.add()), the original object changes. If we use = to point the reference to a new object, we have “broken the link” to the original.

To understand the concept of passing by reference, we will go through an example. Consider the code snippet below:

Java 25
public class SuperList {
public SuperList(int n) {
List<Integer> superList = null;
allocate(superList, n);
}
void allocate(List<Integer> list, int n) {
list = new ArrayList<>(n);
}
}

What happens when we initialize an object of class SuperList? The reference remains null, which may seem counterintuitive.

  • Line 3: Consider superList to be a holder that holds a value of null.

  • Line 4: We are passing a value of null and not the variable superList itself. This is a very important distinction to realize.

  • Line 5: When the program control returns to the constructor, superList is still null because it was never passed in and assigned the ArrayList object.

  • Line 8: When program control reaches this method signature, the list variable is not the variable superList. In fact, it’s a brand-new variable (holder) which receives a copied value of null.

  • Line 9: We initialize the list variable to an object of ArrayList and the list variable will hold the reference or the address of the ArrayList object in the heap memory.

superList holds no reference and is set to null
1 / 5
superList holds no reference and is set to null

In Java, we are copying the reference or the address the reference data type variable holds and passing it, and not the actual variable.

Note that objects are always created in heap memory, and the program variables are only references or addresses to them. So, when we pass a reference data type, the address of the object in the heap memory is copied and passed along. The receiving method can use the reference or the address to manipulate the object in the heap.

To see this behavior in a complete program, we can look at the following demonstration file.

Java
import java.util.ArrayList;
import java.util.List;
public class Demonstration {
public static void main(String[] args) {
SuperList obj = new SuperList(5);
System.out.println("superList = " + obj.sList);
}
}
class SuperList {
public List<Integer> sList;
public SuperList(int n) {
sList = allocate(n);
}
private List<Integer> allocate(int n) {
return new ArrayList<>(n);
}
}
  • Lines 6–7: The main method creates a new SuperList object by invoking its constructor with an initial capacity of 5. After construction, it prints the value of the sList field, which refers to the ArrayList created inside the constructor.

  • Lines 14–16: Inside the constructor, the allocate method is called, and its returned ArrayList reference is assigned directly to the instance variable sList. Because the method returns the newly created object, the constructor stores the correct reference instead of relying on a parameter to be modified.

  • Lines 18–20: The allocate method creates a new ArrayList with an initial capacity of n and returns its reference to the caller. Returning the reference is the correct way to share a newly created object between methods in Java, since method parameters are passed by value and cannot update the caller's reference variable.

AI Powered
Saved
10 Attempts Remaining
Reset
Question

If Java passes object references by value, how is it possible for a method to modify an object’s internal state?

Question

1.

What will be the output of the run method for the IntegerSwap class below?

class IntegerSwap {
    public static void main(String[] args) {
        (new IntegerSwap()).run();
    }
  
    public void run() {
        Integer x = 5;
        Integer y = 9;
        System.out.println("Before Swap x: " + x + " y: " + y);
        swap(x, y);
        System.out.println("After Swap x: " + x + " y: " + y);
    }

    private void swap(Integer a, Integer b) {
        Integer temp = a;
        a = b;
        b = temp;
    }  
}
A.

The output for the two print statements will exactly be the same, i.e., there will be no swapping.

B.

The values will be swapped, so each variable will contain the other’s original value.


1 / 1

Now, to understand the code better, try running the following code, and see it yourself:

Java
class IntegerSwap {
public static void main(String[] args) {
(new IntegerSwap()).run();
}
public void run() {
Integer x = 5;
Integer y = 9;
System.out.println("Before Swap x: " + x + " y: " + y);
swap(x, y);
System.out.println("After Swap x: " + x + " y: " + y);
}
private void swap(Integer a, Integer b) {
Integer temp = a;
a = b;
b = temp;
}
}
  • Lines 1517: Inside the swap method, the variables a and b are merely local stack variables holding copies of the memory addresses of the integer objects. Reassigning a and b inside this method only swaps which memory addresses the local variables point to. It does not alter the original x and y reference variables in the run method, nor does it alter the immutable Integer objects in the heap.

x and y point to integer objects in heap memory.
1 / 6
x and y point to integer objects in heap memory.

Once the program control returns to the run method, x and y keep pointing to the exact same integer objects in the heap because they originally passed in the copies of their references, not themselves.

Question

1.

What will be printed when the following Java code is executed?

class Demonstration {
    public static void main(String[] args) {
        String[] students = new String[10];
        String studentName = "You are an awesome developer";
        
        students[0] = studentName;
        studentName = null;
        
        System.out.println(students[0]);      
    }
}
A.

null

B.

You are an awesome developer


1 / 1

Now, to understand the code better, try running the following code and see it yourself:

Java
class Demonstration {
public static void main(String[] args) {
String[] students = new String[10];
String studentName = "You are an awesome developer";
students[0] = studentName;
studentName = null;
System.out.println(students[0]);
}
}

In Java, variables of type String (and other objects) hold references, not the actual object itself.

  • Line 6: We assign the reference held in studentName to the first index of the students array. At this moment, both variables point to the exact same String object in memory.

  • Line 7: We reassign studentName to null. Assigning null to studentName does not affect other references (like students[0]) that still point to the original String object.

By remembering that Java always passes a copy of the value, whether that value is a primitive number or a memory address pointing to an object, we can confidently trace how data flows through our applications and avoid the common pitfall of the reassignment trap.