Pass by Value and Call by Reference in Java
Overview
Call-by-reference or pass-by-reference is not supported in Java. Java supports pass-by-value only. In pass-by-value, any changes to a parameter inside the called method are not reflected outside the method's scope.
In pass-by-reference, changes made to the parameters inside the method are also reflected outside. Though Java does not support pass-by-reference, we can achieve pass-by-reference in Java for non-primitives.
Introduction
Pointers are interestingly very popular among computer languages. We have this concept in C, C++, Golang, etc. It is known to be a strong concept widely accepted in most languages. However, we don’t have pointers in Java. Before moving forward with what Java has, let’s take a step back and understand a bit about pointers.
Pointers
Basically, a pointer is a variable that stores the memory address of another variable. Talking about pointers, we primarily have two concepts, pass by value and pass by reference (or call by reference). These refer to the methodology that is used while passing a variable as an argument to a method.
As we can see in the above figure, the var variable is present at the memory location 0x7fffa0757dd4, and that address is stored in the pointer variable ptr. *ptr reveals the value of the variable that is present at the memory address stored in ptr. In this case *ptr = 10;
Now, let us understand the difference between pass-by-value and pass-by-reference and how we can link it with function arguments.
Pass by Value in Java
When we pass only the value part of a variable to a function as an argument, it is referred to as pass by value. In this case, any change to the value of a parameter in the called method does not affect its value in the calling method.
As can be seen in the figure below, only the value part of the variable is passed i.e. a copy of the existing variable is passed instead of passing the origin variable. Hence, any changes done to the value of the copy will not have any impact on the value of the original variable. Java supports pass-by-value.
Pass by Reference - Not supported by Java
When reference to the location of a variable is passed to a function as an argument, then it is called pass by reference. In this case, any changes to the value of a parameter inside the function are reflected outside as well.
As we can see in the below figure, the memory address of the variable is stored in a pointer, and this pointer is passed to the function as arguments. In this case, the called function will have access to the original address of the variable. Thus, if we change the value of the variable inside the method, the change is reflected outside the method as well.
Java does not support pass-by-reference as it does not have the concept of pointers. But we can achieve pass-by-reference in Java through the following ways:
How Java Handles Pass by Reference Using Pass by Value
In Java, when we create a variable of class type, the variable holds the reference to the object in the heap memory. This reference is stored in the stack memory.
Hence, when we pass the variable as an argument to a method, we inherently pass a copy of the reference to the object in the heap memory. As a result, the method parameter that receives the object refers to the same object as that referred to by the argument.
Thus, changes to the properties of the object inside the method are reflected outside as well. This effectively means that objects are passed to methods by use of call-by-reference.
Changes to the properties of an object inside a method affect the original argument as well. However, if we change the object altogether, then the original object is not changed. Instead a new object is created in the heap memory and that object is assigned to the copied reference variable passed as argument.
Case with Primitive Data types
This is the case with Java Objects only. Primitive data types are allocated memory in the stack memory, not in the heap memory. Hence, when we pass a variable of primitive data type, a copy of the variable is created in the stack memory, and it is passed as an argument.
As a result, any changes to the copied variable inside the called method are not reflected in the original argument.
Important:
Java does not support pass-by-reference or call-by-reference by any means. The above scenario occurs due to the way objects are created in Java. Java object variables are simply references that point to real objects in the memory heap.
Java supports pass-by-value only. However, copying the reference to an object in the stack memory does not create a clone of the object in the heap memory. Hence when the copied reference is sent as an argument, changes to the fields of the referenced object are reflected in the original fields.
Difference between parameters and arguments:
Parameters: Method parameters are the names listed in the method definition.
Arguments: Method arguments are the real values passed to the method.
Pass by Value Using Java Primitive Types
Example
Output
Explanation:
- When the variables a and b are passed as an argument to the add method, copies of these variables are created in the stack memory.
- These copied variables are passed to the add method.
- Hence, when a is changed inside the add method, it does affect the variable a defined in the main method.
Pass by Value Using Java Objects
Example
Output
Explanation:
- In the above program, variables a and b in the main method store the references of both Integer objects created in the heap memory.
- Passing a and b as arguments to the add method creates copies of these variables/references in the stack memory.
- Point to note here is that these copied variables store the references to the same Integer objects created in the main method.
- Inside the add method, we are changing the object altogether. The a variable inside the add method is made to store the reference to a new Integer object created in the heap memory with the value 10.
- However, due to this operation, only the copied reference variable is affected and the original variable in the main method is not affected.
- Since there are no changes made to the Integer objects created in the main method, the sum inside the main method is 5 only.
Pass by Value for non-primitives
Example
Output
Explanation:
- The called method is able to modify the original object but not replace it with another object.
- In this example, when we create the array object in the main method, a new Integer array object is created in the heap memory. The array variable in the main method holds the reference to the same object.
- On passing array as an argument to the add method creates a copy of that reference in the stack memory. This copied reference/variable is passed to the add method.
- However, the point to note here is that the copied reference points to the same Integer array object that we created in the first step.
- Hence, when we modify the properties of the Integer array object inside the add method using the copied reference, these modifications are reflected in the heap memory.
- If we had reinitialized the array object with array = new Integer[2]; in the add() method, our result would have been different. Let’s see what the result would be.
Example
Output
Explanation:
- Here, we can see that if we reinitialize the array object, which is passed in arguments, the original reference breaks(i.e., we have replaced the original object reference with some other object reference), and the array no longer is referenced to the original array. Hence the value in the main() method didn’t change.
Important Note:
The modification of an object depends on the immutability of a Java class. The classes like Integer, String, Float, Double, Byte, Long, Short, Boolean, and Character are all immutable classes; hence, once created, no modification can be made on the same reference. Hence these classes will strictly follow pass-by-value methodology, same as primitive data types.
Conclusion
- Java supports pass-by-value only.
- Java doesn’t support pass-by-reference.
- Primitive data types and Immutable class objects strictly follow pass-by-value; hence can be safely passed to functions without any risk of modification.
- For non-primitive data types, Java sends a copy of the reference to the objects created in the heap memory.
- Any modification made to the referenced object inside a method will reflect changes in the original object.
- If the referenced object is replaced by any other object, any modification made further will not impact the original object.