Lately, I’ve begun answering questions on StackOverflow. I frequent the Java tag and I’ve noticed one recurring question in particular. Quite often, programmers experience a range of issues related to a misunderstanding of how exactly Java passes method parameters.
First, let’s talk about what the Java Virtual Machine stores on the heap versus on the stack. All
the primatives –
float, and references – are stored on the
stack. Memory stored on the stack is handled entirely by the Operating System. Everything else in
Java – Objects, arrays, and so on – are stored on the heap. Memory allocated on the heap must be
handled by the Java Virtual Machine. The JVM keeps track of all the references and as soon as
there are no references to an object, the JVM flags it for garbage collection. The garbage
collector runs on a daemon thread and frees all of the flagged memory on the heap when it runs.
Here’s a line you may or may not have heard before: Java passes by value. In other words, when you pass a variable to a method, a copy of the variable is made for the method to use. It’s true. What’s sometimes confusing for people though is that Java passes whatever is stored on the stack by value. For an Object or an array, the value stored on the stack is a reference to the allocated memory on the heap. In other words, if you have an object as a parameter, a copy of the pointer is made and it is set to point to the original object.
What exactly does that mean? If you dereference the pointer and change the underlying value on the heap, it does change the initial variable. On the other hand, if you reassign the parameter, you are only changing the method’s local reference to point to a different memory location. The initial variable is not changed.
Consider the class Person.
Let’s say we want to create a method
changePersonToJim(Person personB) that will take
and change the name of the person to Jim and the age of the person to 26. Maybe we could try
someting like this:
What happens? Well, the memory will look like the diagram below just after the method is called (note we are representing memory on the stack with squares and memory on the heap with circles).
Note that a new reference is made and given to the method. Initially, both references reference the same person. What happens after the method executes?
As we can see, when we reassign
personB, a new Person is allocated on the heap. Our reference
in personB then changes to point to this newly allocated Person. What about the initial
personA? As you can see, personA still references the same value on the heap. It is
What if we change our method to look like this?
Since there’s no reassignment, the reference never changes. Both
personB always point
to the same object on the heap. When we call
personB.setAge, we dereference the i
pointer and change the actual value on the heap. The result is that both
point to a Person object with a name of “Jim” and an age of 26.
A second common thing to do is to change the method signature from void to Person. We then return the reference to the newly created Person and we can reassign the original reference to point to it. The old Person that was allocated on the heap then will then have no more references to it and it will be flagged for garbage collection.
Hopefully this post is of some help to you in understanding how exactly Java passes its parameters. If you’re still confused, this StackOverflow answer has many good explanations.