Myth: "Objects are passed by reference, primitives are passed by value"
Some proponents of this then say, "Ah, except for immutable objects which are passed by value [etc]" which introduces loads of rules without really tackling how Java works. Fortunately the truth is much simpler:
Truth #1: Everything in Java is passed by value. Objects, however, are never passed at all.
That needs some explanation - after all, if we can't pass objects, how can we do any work? The answer is that we pass references to objects. That sounds like it's getting dangerously close to the myth, until you look at truth #2:
Truth #2: The values of variables are always primitives or references, never objects.
This is probably the single most important point in learning Java properly. It's amazing how far you can actually get without knowing it, in fact - but vast numbers of things suddenly make sense when you grasp it.
Object x = null; giveMeAString (x); System.out.println (x); [...] void giveMeAString (Object y) { y = "This is a string"; }
the result (if Java used pass-by-reference semantics) would be
This is a string
instead of the actual result:
null
Explaining the two truths above eliminates all of this confusion.
int x = 0; giveMeATen (x); System.out.println (x); [...] void giveMeATen (int y) { y = 10; }Now, the above doesn't print out "10". Why not? Because the value "0" was passed into the method
giveMeTen
, not the
variable itself. Exactly the same is true of reference variables -
the value of the reference is passed in, not the variable itself.
It's the same kind of copying that happens on variable assignment.
The first code snippet, if inlined, is equivalent to:
// Before the method call Object x = null; // Start of method call - parameter copying Object y = x; // Body of method call y = "This is a piece of string."; // End of method call System.out.println (x);
If you want to think pictorially, you might find my "objects are balloons, references are pieces of string" analogy helpful.
This analogy also explains garbage collection (apart from the
java.lang.ref
API, which does "odd" things :) - a balloon
floats away unless it is tethered down to something. The balloons
can have further holders on them (instance variables), but just
because two balloons are holding onto each other doesn't stop them
from floating away. (Cyclic references are collected.) Any balloon
representing an object which is in the middle of having a method
invoked is tethered to the JVM. (Apologies for not being able to
phrase that more succinctly - all I mean is that anything in an
active thread's stack isn't garbage collected.)
A more formal analysis
This excellent formal analysis of the question is courtesy of
Dale King
Question: Does Java pass objects by reference or by value?
Answer:
Since it makes no sense to begin any argument without agreed upon
defintions let's formally define our terms. I will use abstract
pseudocode to keep the issue from being clouded by the idiom of a
particular language. The source of my information is the book
"Advanced Programming Language Design" by Raphael A. Finkel.
For those unfamiliar with the term below an L-value is an expression that can appear on the left side of an assignment statement. It is basically a way to address where a variable is stored. Variables and other ways to refer to locations in memory are L-values. Most expressions are not L-values, e.g. ( x * 2 )
We assume the presence of a procedure named f that takes a formal parameter s. We call that function giving it an actual parameter g.
The calling code:
f( g )The function:
procedure f( s ) begin -- body of the procedure end;There are several parameter passing semantics that have been proposed or used:
Now that we have some definitions of terms we can return to the question. Does Java pass objects by reference or by value?
The answer is NO! The fact is that Java has no facility whatsoever to pass an object to any function! The reason is that Java has no variables that contain objects.
The reason there is so much confusion is people tend to blur the distinction between an object reference variable and an object instance. All object instances in Java are allocated on the heap and can only be accessed through object references. So if I have the following:
StringBuffer g = new StringBuffer( "Hello" );The variable g does not contain the string "Hello", it contains a reference (or pointer) to an object instance that contains the string "Hello".
So if I then call f( g ), f is free to modify its formal parameter s to make it point to another StringBuffer or to set it to null. The function f could also modify the StringBuffer by appending " World" for instance. While this changes the value of that StringBuffer, the value of that StringBuffer is NOT the value of the actual parameter g.
Imagine for instance if I set g to null before passing it to f. There is no StringBuffer now to modify and f can in no way change the value of g to be non-null.
The bottom line is Java only has variables that hold primitives or
object references. Both are passed by value.
Ways to avoid needing pass-by-reference
This section is courtesy of Chris Smith. (Updated by Jon Skeet.)
There are good reasons that Java excluded the idea of pass-by-reference from its language design, and when writing Java applications it's best to do as Java does. There are elegant solutions to all common problems that may be solved with pass-by-reference in other languages. Before I get there, though, let's look at some of the problems of pass by reference.
Pass by reference mixes inputs and outputs of code. This is the fundamental problem with the technique. In Java, a programmer can assume that variables will not change their value when passed as parameters to a method. In languages with pass by reference semantics, this basic assumption cannot be made.
Pass by reference confuses the interface to a method. Methods written using pass-by-reference semantics can have extremely complex interfaces that are difficult for client programmers to learn and understand. That said, you may be left with a situation where you feel the need to use pass-by-reference in an application. There are two major reasons to use pass by reference, and each has its own solution:
First, pass by reference is used in many languages to reduce the costs of a method call, preventing the copying of large amounts of data. This is a non-issue in Java. The problem is solved by simply realizing that in Java, the values passed to a method are either primitive data or object references, which cannot be large enough to make this a real issue. Objects themselves can be very large, but are never passed to methods.
Second, pass by reference allows the variable to be changed, and the changed value can be seen in client code. The solution here is to refactor the application to use the return value for this purpose. If a parameter is an "in-out" parameter, then its original value should be passed into the method and its result moved to the return value. The client code may then look like this:
a = someMethod(a);This is the real reason why pass by reference is used in many cases - it allows a method to effectively have many return values. Java doesn't allow multiple "real" return values, and it doesn't allow pass by reference semantics which would be used in other single-return-value languages. However, here are some techniques to work around this:
Point
class, pass an object reference by value, and
update the object's values within the method.
Back to the main page.