TIL-27: Is Java Pass by Value or Pass by Reference? — A little bit of Memory Management
“Today I learned that java is pass-by-value”.
This is a common interview question about Java when it comes to memory management aspects of things. In this post, I will share what I learned about this question.
- What happens when we create a new object and a primitive value?
- Is Java pass-by-value or pass-by-reference?
Creating New Objects
In Java, memory management is done by the JVM (Java Virtual Machine) for us. This means that we do not have to allocate/deallocate memory manually. Let’s see what happens when we create a new object.
Let’s go through the numbered sections one by one.
I. Declaration of a Primitive Data Type
For Primitive data types, memory is allocated by the JVM at the time of declaration. When we call “int a” JVM allocates memory enough for an integer (int) value.
II. Assigning a Value to Primitives
Here we set the value (100) for that part (int a) of the memory.
III. Declaration of an Object
A variable named “ageOfEmpires” created as the reference to a “Game” object. The memory allocation for the object itself is not at this stage. Only the memory for the reference variable is allocated.
IV. Calling new for an Object
The “new” keyword ask JVM to allocate enough memory for the object type “Game” so that it can fit in the incoming object.
V. Initializing the Game Object
When the memory is allocated for the Game object, the call to the constructor of that class will create the actual Game instance and store it in the heap.
VI. Pointing to the Actual Object
And with the help of assignment operator “=”, the object’s reference (ageOfEmpires) points to the address of the newly created Game object. Now our reference variable holds the address of the Game object, and not the object itself.
Pass-by-Value or Pass-by-Reference?
Now, learning how Java handles these operations, let’s try to answer the real question, “Is Java Pass-by-Value or Pass-by-Reference?”. Let’s look at an example to find an answer.
What happened here?
- In the Lines 2 and 3, we created two primitive integer type variables a and b and gave them values 100 and 999.
- We then print the value of “a”, and try to swap the values of a and b and then print the value of “a” again. And if we do that, the result we got is:
- It shows us that the swap method did not work as expected, because java is pass-by-value and not pass-by-reference. Now, let’s try it for objects!
- If we look at Lines 9 and 10, we see that two Game objects are created with two different GameType values. The wow and ageOfEmpires have RPG and STRATEGY GameType values. Knowing how Java creates these objects we can try swapping them.
- Then, print the GameType value of ageOfEmpires, swap it with “wow” and then print the GameType value of ageOfEmpires again. What should we expect? STRATEGY and RPG right? Well, no.
- What happened there? In the swap method at lines 24–28, we pass the reference variable “ageOfEmpires” which only shows the address to the actual “Game@898 — Age of Empires” instance, and the reference variable “wow” which only shows the address to the actual “Game@899 — World of Warcraft” instance. Since Java is pass-by-value, the value we passed is copied and did not touch the actual objects in the Heap. Thus, not causing any change, and not swapping really.
Bonus: If only the values are passed, how could we make changes to the actual object then?
Using an object’s getter/setter methods will interact with the object itself, instead of the copied reference. Here when we call changeType() method, the “ageOfEmpires” reference that shows the actual “Game@898” object is copied, however, when we call “.setGameType()” on that reference, it calls this method on where the Game@898 is located in the memory, thus changing the object itself.
Conclusion
Java is always pass-by-value!
Cheers!
References
Great reads on this topic, I suggest you read them all.