Chris said:
Most of the time, though, people who object to this fact *do* understand
the behavior of Java, and just have a fuzzy definition of "pass by
reference". When pressed, they will generally degrade to saying that
the meaning of "pass by reference" is language-specific, thus creating a
circular argument that you can't possibly disprove. Hopefully, they
will later come to their senses.
Actually I find that more often it is not understanding the difference
between the object living on the heap and the variable that refers to
it. When people say objects are passed by reference they are showing
this confusion.
Here is the canned response I put together on the subject:
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:
value
The value of the actual parameter is copied into the formal
parameter when the procedure is invoked. Any modification of
the formal parameter affects only the formal parameter and
not the actual parameter. This is the most common form of
parameter passing and is the only one provided in C and Java.
result
The value of the formal parameter is copied into the actual
parameter when the procedure returns. Modifications to the
formal parameter do not affect the formal parameter until the
function returns. The actual parameter must be an L-value. It
is usually invalid to pass the same L-value to more than one
result parameter, but the compiler cannot always detect this.
The best example of this is out parameters in CORBA.
value result
Combination of value and result semantics. The best example of
this are inout parameters in CORBA.
reference
The L-value of the formal parameter is set to the L-value of the
actual parameter. In other words, the address of the formal
parameter is the same as the address of the actual parameter. Any
modifications to the formal parameter also immediately affect the
actual parameter. FORTRAN only has reference mode (expressions are
evaluated and stored in a temporary location in order to obtain an
L-value). C++ has reference parameters by putting a & before the
formal parameter name in the function header. Reference mode can
be simulated in C using pointers and adding the & to the actual
parameter and dereferencing the formal parameter within the
function.
readonly
Can use either value or reference mode, but modification of the
formal parameter is forbidden by the compiler.
macro
name
These two have been used in the past, but are very much out of favor
because they are confusing and difficult to implement. Therefore I
won't bother trying to explain them.
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.
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.