loading...
Cover image for Does Java pass only by value?

Does Java pass only by value?

vivekworks profile image Vivek T S Updated on ・8 min read

When it comes to Java in calling a method and passing arguments as primitives, there’s no doubt that it follows the pass by value model. Trouble in understanding comes when dealing with Objects. Since reference types store the address of the object, when reference types are passed as arguments, it’s the memory address of the object that is passed and any change to the object’s nature (instance variables) inside the called method reflects in the caller.

This raises the question, Does Java pass by reference when it comes to reference types?

Variables
Before getting into the discussion of pass by value/reference, let’s understand about the kind of variables apart from the standard variable that were available to programmers in the languages that predate Java.

Pointers — In C/C++, there are special type of variables that stored the address of any type of variable called Pointers. Pointers are usually assigned with address of another variable or they're made to point to nothing (NULL pointer). Pointers are the reference types in Java.

Reference Variables — In C++, another special type of variable that acts as an alias/alternative name to the original variable exists called Reference Variable. So, any change to the original variable or it’s aliases affects everywhere. Reference variables are declared using & operator and must be initialized during creation as it doesn’t accept NULL.

Look at below code example in C++. Note that * and & operators have different functionality in a declaration and an expression.

#include <iostream>
using namespace std;

int main(){
    int var = 45;                //Simple  variable  , stores 45 as its value
    int* varPtr = &var;          //Pointer variable  , stores the address of var as its value
    int** varPtrPtr = &varPtr;   //Pointer variable  , double pointer, stores the address of varPtr as its value
    int& varRef = var;           //Reference variable, acts as a reference to var
    int* varRefPtr = &varRef;    //Pointer variable  , stores the address of varRef as its value  

    cout << "\nvar       : " << var;
    cout << "\nvarPtr    : " << varPtr;
    cout << "\nvarPtrPtr : " << varPtrPtr;
    cout << "\nvarRef    : " << varRef;
    cout << "\nvarRefPtr : " << varRefPtr;
}


/* *
 * Sample Output
 * --------------------
 * var       : 45
 * varPtr    : 0x61fdb4
 * varPtrPtr : 0x61fda8
 * varRef    : 45
 * varRefPtr : 0x61fdb4
 * 
 * */

From the above output, we can see that varPtr stored the address of var whereas varRef stored the value of var. Similarly, the address of varRef i.e., varRefPtr is identical to the address of var i.e., varPtr. This proves that the pointers and reference variables are different conceptually.

Pass by value vs Pass by reference in C++
Now that we understood different types of variables available, let’s see a sample swap program in C++ employing these different variables. Here is summary of various functions in the program.

  • swapByValue — This function takes in two simple variables and swaps using a temp variable.

  • swapByPointer — This function takes in two pointer variables and attempts swapping. Note that here pointer dereferencing isn’t used to show the difference between pointer and reference variables.

  • swapByReference — This function takes in two reference variables and swaps them.

  • swapByPointerDereference — This function takes in two pointer variables and dereferences it using the address.

#include <iostream>
using namespace std;

void swapByPointerDereference(int* a4, int* b4){
    cout << "\nEnters : a4 value is " <<a4 <<", b4 value is " << b4;
    cout << "\nEnters : a4 address is " << &a4 <<", b3 address is " << &b4;
    int temp = *a4;
    *a4 = *b4;
    *b4 = temp;
    cout << "\nExits  : a4 value is " <<a4 <<", b4 value is " << b4;
    cout << "\nExits  : a4 address is " << &a4 <<", b4 address is " << &b4 << "\n";
}

void swapByReference(int& a3, int& b3){
    cout << "\nEnters : a3 value is " <<a3 <<", b3 value is " << b3;
    cout << "\nEnters : a3 address is " << &a3 <<", b3 address is " << &b3;
    int temp = a3;
    a3 = b3;
    b3 = temp;
    cout << "\nExits  : a3 value is " <<a3 <<", b3 value is " << b3;
    cout << "\nExits  : a3 address is " << &a3 <<", b3 address is " << &b3 << "\n";
}

void swapByValue(int a1, int b1){
    cout << "\nEnters : a1 value is " <<a1 <<", b1 value is " << b1;
    cout << "\nEnters : a1 address is " << &a1 <<", b1 address is " << &b1;
    int temp = a1;
    a1 = b1;
    b1 = temp;
    cout << "\nExits  : a1 value is " <<a1 <<", b1 value is " << b1;
    cout << "\nExits  : a1 address is " << &a1 <<", b1 address is " << &b1 << "\n";
}

void swapByPointer(int* a2, int* b2){
    cout << "\nEnters : a2 value is " <<a2 <<", b2 value is " << b2;
    cout << "\nEnters : a2 address is " << &a2 <<", b2 address is " << &b2;
    int* temp = a2;
    a2 = b2;
    b2 = temp;
    cout << "\nExits  : a2 value is " <<a2 <<", b2 value is " << b2;
    cout << "\nExits  : a2 address is " << &a2 <<", b2 address is " << &b2 << "\n";
}

int main(){
    int a1 = 45;
    int b1 = 65;
    int a2 = 15;
    int b2 = 35;
    int a3 = 25;
    int b3 = 55;
    int a4 = 75;
    int b4 = 95;

    cout << "\n*-----Swap By Value-----*";
    cout << "\nBefore : a1 value is " << a1 << ", b1 value is " << b1;
    cout << "\nBefore : a1 address is " << &a1 << ", b1 address is " << &b1;
    swapByValue(a1, b1);
    cout << "After  : a1 value is " << a1 << ", b1 value is " << b1 << "\n";
    cout << "After  : a1 address is " << &a1 << ", b1 address is " << &b1 << "\n";

    cout << "\n*-----Swap By Pointer-----*";
    cout << "\nBefore : a2 value is " << a2 << ", b2 value is " << b2;
    cout << "\nBefore : a2 address is " << &a2 << ", b2 address is " << &b2;
    swapByPointer(&a2, &b2);
    cout << "After  : a2 value is " << a2 << ", b2 value is " << b2 << "\n";
    cout << "After  : a2 address is " << &a2 << ", b2 address is " << &b2 << "\n";

    cout << "\n*-----Swap By Reference-----*";
    cout << "\nBefore : a3 value is " << a3 << ", b3 value is " << b3;
    cout << "\nBefore : a3 address is " << &a3 << ", b3 address is " << &b3;
    swapByReference(a3, b3);
    cout << "After  : a3 value is " << a3 << ", b3 value is " << b3 << "\n";
    cout << "After  : a3 address is " << &a3 << ", b3 address is " << &b3 << "\n";

    cout << "\n*-----Swap By Pointer Dereference-----*";
    cout << "\nBefore : a4 value is " << a4 << ", b4 value is " << b4;
    cout << "\nBefore : a4 address is " << &a4 << ", b4 address is " << &b4;
    swapByPointerDereference(&a4, &b4);
    cout << "After  : a4 value is " << a4 << ", b4 value is " << b4 << "\n";
    cout << "After  : a4 address is " << &a4 << ", b4 address is " << &b4 << "\n";

}


/* *
 * Sample Output
 * ---------------
 *
 * *-----Swap By Value-----*
 * Before : a1 value is 45, b1 value is 65
 * Before : a1 address is 0x61fe1c, b1 address is 0x61fe18
 * Enters : a1 value is 45, b1 value is 65
 * Enters : a1 address is 0x61fde0, b1 address is 0x61fde8
 * Exits  : a1 value is 65, b1 value is 45
 * Exits  : a1 address is 0x61fde0, b1 address is 0x61fde8
 * After  : a1 value is 45, b1 value is 65
 * After  : a1 address is 0x61fe1c, b1 address is 0x61fe18
 * 
 * *-----Swap By Pointer-----*
 * Before : a2 value is 15, b2 value is 35
 * Before : a2 address is 0x61fe14, b2 address is 0x61fe10
 * Enters : a2 value is 0x61fe14, b2 value is 0x61fe10
 * Enters : a2 address is 0x61fde0, b2 address is 0x61fde8
 * Exits  : a2 value is 0x61fe10, b2 value is 0x61fe14
 * Exits  : a2 address is 0x61fde0, b2 address is 0x61fde8
 * After  : a2 value is 15, b2 value is 35
 * After  : a2 address is 0x61fe14, b2 address is 0x61fe10
 * 
 * *-----Swap By Reference-----*
 * Before : a3 value is 25, b3 value is 55
 * Before : a3 address is 0x61fe0c, b3 address is 0x61fe08
 * Enters : a3 value is 25, b3 value is 55
 * Enters : a3 address is 0x61fe0c, b3 address is 0x61fe08
 * Exits  : a3 value is 55, b3 value is 25
 * Exits  : a3 address is 0x61fe0c, b3 address is 0x61fe08
 * After  : a3 value is 55, b3 value is 25
 * After  : a3 address is 0x61fe0c, b3 address is 0x61fe08
 * 
 * *-----Swap By Pointer Dereference-----*
 * Before : a4 value is 75, b4 value is 95
 * Before : a4 address is 0x61fe04, b4 address is 0x61fe00
 * Enters : a4 value is 0x61fe04, b4 value is 0x61fe00
 * Enters : a4 address is 0x61fde0, b3 address is 0x61fde8
 * Exits  : a4 value is 0x61fe04, b4 value is 0x61fe00
 * Exits  : a4 address is 0x61fde0, b4 address is 0x61fde8
 * After  : a4 value is 95, b4 value is 75
 * After  : a4 address is 0x61fe04, b4 address is 0x61fe00
 * 
*/

The output clearly shows that only during the execution of swapByReference routine, the value & address of variables remained the same. Though swapByPointerDereference function swapped the values, they just employed pass by value with address and performed dereferencing. It is evident from the difference in the addresses of variables between the caller and called function. Thus it proves that only through reference variables, pass by reference can be employed.

Pass by value vs Pass by reference in Java
In Java, there are no such variables as reference variables. The reference type that store the address of an object is just a pointer to the object.

Lets see a similar swap program to the one seen above in Java language. The program can be contains three methods and they do the following,

  • swapByValue — Method that swaps two primitives
  • swapByReferenceType — Method that swap two reference types
  • swapByObjectManipulation — Method that swaps objects by doing something similar to pointer dereferencing using Java dot operator
class Person {
    int id;
    String name;

    Person(int id, String name){
        this.id = id;
        this.name = name;
    }
}

public class PassByModel {
    public static void main(String... args) {
        Person p1 = new Person(1, "Person1.0");
        Person p2 = new Person(2, "Person2.0");
        Person p3 = new Person(3, "Person3.0");
        Person p4 = new Person(4, "Person4.0");
        int a = 1, b = 2;

        System.out.println();
        System.out.println("*-----Swap By Value-----*");
        System.out.println("Before : a is "+a+", b is "+b);
        swapByValue(a, b);
        System.out.println("After  : a is "+a+", b is "+b);
        System.out.println();

        System.out.println("*-----Swap By Reference Type-----*");
        System.out.println("Before : p1 is "+p1+", p2 is "+p2);
        System.out.println("Before : p1 id is "+p1.id+", p1 name is "+p1.name+"; p2 id is "+p2.id+", p2 name is "+p2.name);
        swapByReferenceType(p1, p2);
        System.out.println("After  : p1 is "+p1+", p2 is "+p2);
        System.out.println("After : p1 id is "+p1.id+", p1 name is "+p1.name+"; p2 id is "+p2.id+", p2 name is "+p2.name);
        System.out.println();

        System.out.println("*-----Swap By Object Manipulation-----*");
        System.out.println("Before : p3 is "+p3+", p4 is "+p4);
        System.out.println("Before : p3 id is "+p3.id+", p3 name is "+p3.name+"; p4 id is "+p4.id+", p4 name is "+p4.name);
        swapByObjectManipulation(p3, p4);
        System.out.println("After  : p3 is "+p3+", p4 is "+p4);
        System.out.println("After  : p3 id is "+p3.id+", p3 name is "+p3.name+"; p4 id is "+p4.id+", p4 name is "+p4.name);

    }

    static void swapByValue(int a, int b) {
        System.out.println("Enters : a is "+a+", b is "+b);
        int temp = a;
        a = b;
        b = temp;
        System.out.println("Exits  : a is "+a+", b is "+b);
    }

    static void swapByReferenceType(Person p1, Person p2) {
        System.out.println("Enters : p1 is "+p1+", p2 is "+p2);
        Person temp = p1;
        p1 = p2;
        p2 = temp;
        System.out.println("Exits  : p1 is "+p1+", p2 is "+p2);
    }

    static void swapByObjectManipulation(Person p3, Person p4) {
        System.out.println("Enters : p3 is "+p3+", p4 is "+p4);
        Person temp = p3;
        p3.id = p3.id;
        p3.name = p3.name;
        p4.id = temp.id;
        p4.name = temp.name;
        System.out.println("Exits  : p3 is "+p3+", p4 is "+p4);
    }
}

/*
 * Sample Output
 * -------------
 *
 * *-----Swap By Value-----*
 * Before : a is 1, b is 2
 * Enters : a is 1, b is 2
 * Exits  : a is 2, b is 1
 * After  : a is 1, b is 2
 * 
 * *-----Swap By Reference Type-----*
 * Before : p1 is Person@18e8568, p2 is Person@33e5ccce
 * Before : p1 id is 1, p1 name is Person1.0; p2 id is 2, p2 name is Person2.0
 * Enters : p1 is Person@18e8568, p2 is Person@33e5ccce
 * Exits  : p1 is Person@33e5ccce, p2 is Person@18e8568
 * After  : p1 is Person@18e8568, p2 is Person@33e5ccce
 * After  : p1 id is 1, p1 name is Person1.0; p2 id is 2, p2 name is Person2.0
 * *-----Swap By Object Manipulation-----*
 * Before : p3 is Person@326de728, p4 is Person@25618e91
 * Before : p3 id is 3, p3 name is Person3.0; p4 id is 4, p4 name is Person4.0
 * Enters : p3 is Person@326de728, p4 is Person@25618e91
 * Exits  : p3 is Person@326de728, p4 is Person@25618e91
 * After  : p3 is Person@326de728, p4 is Person@25618e91
 * After  : p3 id is 3, p3 name is Person3.0; p4 id is 3, p4 name is Person3.0
 *  
 */

The methods swapByValue and swapByReference produce similar output. Even though the reference type holds the address of an object as its value (Person), the value is just assigned onto the parameter and these parameters are no direct references to the object created in the caller. Java language doesn’t allow a programmer to create reference variables. It can be concluded from the above experiment that pass by reference is never really allowed in Java.

Java is designed with C as the fundamental programming model and C++ for the OOP principles. Java passes values to methods and these values are just copied across parameters be it primitives or reference types. It is often misunderstood that since the reference types store the address of an object, it is passed by reference. Reference types are pointers and not reference variables. In fact, there are no reference variables or aliases/alternatives in Java as in C++.

Answering the question, Java passes only by value for both primitives and reference types!!!

Useful links on the topic
https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value
https://stackoverflow.com/questions/1961146/memory-address-of-variables-in-java
https://stackoverflow.com/questions/14612314/how-are-variable-names-stored-in-memory-in-c
https://stackoverflow.com/questions/48204770/get-name-of-variable-from-its-address

Posted on by:

vivekworks profile

Vivek T S

@vivekworks

I'm an Applications Developer currently employed @ Oracle

Discussion

markdown guide
 
  • "Pointers are declared using * operator and can only be assigned with an address of another variable or NULL (called Null Pointer)."

This is not quite true.

  1. The * in a declaration in C or C++ is not an operator.
  2. A pointer need not be assigned the address of a variable. Consider p = p + 1;
  3. NULL is not a pointer -- it is the null pointer constant -- an expression evaluating to something equivalent to 0 or (void *)0 -- which means that in some contexts it doesn't produce a pointer value at all.
 

Thank you for the correction. I'll verify and update the post.