Call by Value and Call by Reference in Java

In Java programming language, method can be called in two ways, which is known as Call by Value and Call by Reference. These two ways differentiate by the type of values passed to method as parameters.The parameters passed to a method are called actual parameters whereas the parameters received by a method are called formal parameters.

These concepts are crucial to understand for Java developers as they dictate how data is passed between methods, impacting the behavior of the program. In this tutorial, we'll delve into the differences between Call by Value and Call by Reference in Java, exploring examples to solidify the concepts.


Call by Value

Call by value method copies the value of an argument into the formal parameter of that function. The two types of parameters are stored in different memory locations. Therefore, changes made to the parameter inside functions body are not reflected in actual parameters of the caller.

Java program using call by value.

public class CallByValue {
    private static void increment(int val) {
        val++;
        System.out.println("Inside method");
        System.out.println("Value = " + val);
    }

    public static void main(String[] args) {
        int num = 10;
        System.out.println("Before calling: " + num);
        increment(num);
        System.out.println("After calling: " + num);
    }
}
Output
Before calling: 10
Inside method
Value = 11
After calling: 10

In above java program, we are calling "increment" method by passing an integer variable num as parameter using call by value. The value of variable num is copied into formal parameter val.

The values of num and var variable is stored at different memory locations. Hence, incrementing the value of parameter var inside "increment" method will not change the value of num.


Call by Reference

Call by reference method copies the address of an argument into the formal parameter. In this method, the address is used to access the actual argument used in the function call. Both the actual and formal parameters refer to the same memory locations. Any changes made to the parameter inside the function body are actually reflected in actual parameters of the caller.

Java program using call by reference.

class Length {
    int length;

    Length(int length) {
        this.length = length;
    }

    public void print() {
        System.out.println("Length= " + this.length);
    }
}

public class CallByReference {
    private static void increment(Length lengthArg) {
        lengthArg.length = lengthArg.length + 1;
    }

    public static void main(String[] args) {
        Length lengthObject = new Length(10);
        // Before increment call
        lengthObject.print();
        // Call increment method using
        // call by reference
        increment(lengthObject);
        // After increment call
        lengthObject.print();
    }
}
Output
Length= 10
Length= 11

In above java program, we are calling "increment" method by passing object reference as parameter using call by reference.

Both lengthObject and lengthArg pointing towards same object at the same memory location. Hence, incrementing lengthArg inside "increment" method will change the value of lengthObject.


Difference between Call by Value and Call by Reference

Call by Value Call by Reference
A copy of the variable is passed to method. A reference to a variable is passed to method.
Actual and formal arguments will be created in different memory locations. Both actual and formal parameters refer to the same memory locations.
Original parameter value is not modified by the changes inside method body. The original parameter value gets modified by the changes inside method body.
Values of variables are passed by the simple technique. Pointer/reference variables are necessary to define to store the address values of variables.

Java's Approach: Call by Value for Primitive Types, Call by Sharing for Objects

Java is often described as a "Call by Value" language. However, it's important to clarify that Java is "Call by Value" for primitive types and "Call by Sharing" for objects.
  • Call by Value for Primitive Types : For primitive data types (e.g., int, float, char), the actual value is passed to the method. Any modifications made to the parameters inside the method do not affect the original variables.

  • Call by Sharing for Objects : When objects are passed as arguments, the reference to the object is passed by value. The reference points to the memory location of the object, not the object itself. As a result, modifications to the object's state inside the method are reflected outside the method.

Common Misconceptions

  • Java is Strictly Call by Value : While it's often stated that Java is strictly Call by Value, it's crucial to recognize the distinction between primitive types and objects. For primitive types, the value is passed directly, adhering to Call by Value principles. For objects, it's more accurate to say Java is "Call by Sharing," as the reference to the object is passed by value.

  • Java Supports Call by Reference : Java does not support true Call by Reference. In languages that support Call by Reference, modifying parameters inside a method directly affects the original variables. In Java, for primitive types, this is not the case. However, for objects, the effect might seem similar due to the passing of references

Practical Implications

Understanding whether a language employs Call by Value or Call by Reference is crucial for programming. It influences how modifications to variables are handled, impacting the behavior of functions and methods.
  • Efficient Memory Usage : Call by Value can be more memory-efficient for primitive types since only the values are passed. Call by Sharing for objects can be efficient for large objects, as only the reference is passed, not the entire object.

  • Predictable Behavior : Understanding whether changes to parameters affect the original variables helps developers write more predictable and maintainable code. In Call by Value, modifications are local to the method, providing a clear boundary. In Call by Sharing, modifications might affect external variables, requiring careful consideration.

Conclusion

In Java, the concepts of Call by Value and Call by Sharing are essential for understanding how data is passed between methods. While Java follows Call by Value for primitive types and Call by Sharing for objects, it's important to clarify these concepts to avoid common misconceptions. As you progress in your Java programming journey, consider the implications of these mechanisms in different scenarios, ensuring your code behaves as intended and remains efficient.