- A common misconception exists that parameters in Java are passed by reference. They are not. Parameters are passed by value. The misconception arises from the fact that all apparent object variables are really object references. This leads to some unexpected results if you do not understand exactly what is happening.
From "The Java Programming Language Second Edition", by
Ken Arnold and James Gosling (ISBN 0-201-31006-6
) (probably from page 40--don't have the book handy right now):
- Some people will say incorrectly that objects in Java are "pass by reference." The term pass by reference properly means that when an argument is passed to a function, the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter, the value in the calling code will be changed because the argument and parameter use the same slot in memory. [...] There is exactly one ParameterPassing mode in Java--pass by value--and that helps keep things simple.
Discussion moved to JavaDoesntPassByValue
I don't know about SunMicrosystems
, and I don't know JamesGosling
, but KenArnold
I trust implicitly on all topics, and so should you, so the above suffices for argument by authority.
For those who need more to be convinced: you cannot directly write a swap function in JavaLanguage
to swap the values of two variables passed as parameters, whether they are objects or scalars. Yet a swap function is trivial in any language that allows PassByReference
, period, including the pointer to a method's object. It's that simple.
The real problem here is that Java is fond of claiming that it doesn't have pointers; that's part of its claim to fame as a safer language. So although it does in fact have pointers (cleaned up to be much safer than in CeePlusPlus
), it had to call them something other than "pointer". Sun chose to call them "references", even though that's not what the rest of the industry usually means when distinguishing a "pointer" from a "reference". Java "references" are certainly not like e.g. C++ "references". Java has pointers to objects, which are passed by value to methods.
This illustrates just how badly you can confuse people by using non-standard meanings for words. It's often better to make up brand new words than to distort the meaning of an existing word.
It is nice to see that Java so effectively clears up an issue that was very confusing in C++. :-)
It does indeed. JavaLanguage
uses the model that was first introduced by LispLanguage
, and that was later followed by SmalltalkLanguage
, etc.. Note that in the Java/Lisp/Smalltalk/Python/Scheme/... model, all objects have "object identity" separate from the variable (if any) to which they are assigned, i.e.
x = y
will make x and y refer to the same object. This model immediately allows indirection and aliasing, without further ado. Function call leads to the parameter variables of the function being assigned to the actual arguments of the call.
, assignment is a copying assignment, i.e.
x = y
copies the contents form y into x. In C (and Pascal without var keyword), function call leads to the parameter variables of the function being assigned
to the actual arguments. This is the same as the Lisp model: however,
the definition of ``assignment'' is different!
"Java is a pass by value language. However it's common to pretend that we have both pass by value and pass by reference."
argument moved below for a hopefully decent answer
Stated without citing any language specs, using algebraic notation, or complex reasoning, here's my "twelve step program" to help people understand why it is 100% correct to say that JavaPassesByValue
(suitable even for Java novices, I hope):
- The first thing is to understand the difference between a primitive and an object:
- A primitive carries only a single value for a single purpose, and it takes up a fixed number of bytes depending on the type of the primitive (there are quite a few types, commonly taking four bytes each, but there's more to it than needs to be explained here).
- Objects are complex ensembles of data; they carry any number of primitive values (aka "members") inside of them, and they take up as many bytes as they need to -- some basic overhead plus all the space for all of the primitives they hold (there's of course more to it than that, but again we don't need to go into it here).
- There are nominally two types of primitive values that you can manipulate in a Java program:
- the assorted numerical value types (such as long, double and even char and boolean) all of which are functionally similar even if their bit encoding differs. All of them evaluate to some sort of numerical value that is then directly consumed as a number. There's nothing else to it.
- an object reference value (or reference). These also evaluate to numbers, but the value isn't mathematically interesting - it's essentially just a memory pointer -- specifically a pointer to where the referenced object exists in memory.
- References are neither a kludgy nor a "deep" concept; they are just like long or double values in that they are simple, multi-byte primitives that are evaluated in a predetermined way at runtime.
- When used in a program, a object reference gives the holder seemingly-direct access to the referenced object's members via a ".memberName" syntax. The programmer never sees the reference as an address or pointer -- the reference acts as if it were the actual object. In essence, the "pointer nature" of references is an invisible concept.
- Variables in Java can only hold primitives: Either numerical values or object references.
- You do not and cannot directly "hold" an object in a variable. What you can do is hold an object reference value, which as explained above will appear to be an actual object for the most part.
- You can make as many copies of numerical value primitives as you want, and all of them are functionally equal. For instance, assign some value to an long variable, and make 99 more copies of it into other variables of the same type. All of the copies and the original are equal and indistinguishable from each other, right? Now, if you assign a new value to any one of them (using the assignment operator), only that one will have its value changed; the other 99 will still hold their original numerical values.
- Likewise, you can make as many copies of a reference as you want, and all of them will evaluate equally to the same thing -- they will give you equal access to the same referenced object. Now, if you assign a different value to any one of the copies, only that one will be changed. It will now reference whatever alternate object you reassigned it to point to. And just as with the numeric primitives, the other 99 will remain unchanged, all pointing to the original object. It is critical to understand, we're talking about 100 references all pointing to the same, single instance of an object. Not 100 identical copies of an object. This subtle difference gets a lot of people into trouble.
- Any alteration of an object through any copy of a reference to it will be immediately visible through all copies. Make a copy of an object reference. Call a mutating method on either one, and the other will be able to show you the change. This is because they share the same physical object -- you are just dealing with references to a single thing.
- Here's the key thing we've been building up to:
- Java methods can only pass primitive values down.
- Whatever primitive data you pass gets copied into the called function's local environment.
- Any assignments to that value will be reflected only in the local copy, and the caller's original copy will still reflect the original value when the method returns.
- Pass a ''long' variable, whose value is for instance 10, into a method. While in the method, set the method's copy of the variable to any other value. When you return to the caller, the original variable still holds a 10.
- Now look at that example in the case of an object reference value instead of a numerical value. This means that if you overwrite the reference's value (by assigning it to point to a different object) you are only changing the local copy; the caller's original still points to the original object.
- Here's the tricky part that often confuses people about reference vs value: You can't assign over the value of passed reference to make it point to a different object upon return, but since any copy of the reference is just as good as the original in terms of accessing the single object they share, a passed-in reference can be used to change the data inside the object. Based on what we covered a few bullets ago, the changes will also be seen in original reference when the method call returns.
Yes, it may look like JavaDoesntPassByValue
, but now you can see why it's true that JavaPassesByValue
Move this here from above, since counter-example is long.
"Despite Gosling's insistence on this matter, I fail to see how anyone can defend the position that passing a reference to an object does not constitute pass-by-reference. That you cannot pass references to a few things (parameter memory, local variable memory, and instance variable memory) is mildly interesting and somewhat precludes the amusing notion of "out" parameters. Those unimportant limitations don't make Java a pass-by-value language. Next time you pass an object into a method that unexpectedly alters it, tell me again that Java is pass-by-value."
I can and will argue that, a copy of a reference is not the same thing as having the same reference. This is the difference between a normal object argument in CeePlusPlus
and an alias. Quite simply, JavaLanguage
doesn't do aliases, if it did I would be able to do the following:
Integer x = new Integer(1);
System.out.println("x is " + x);
void addOne(Integer originalValue)
value = new Integer(originalValue.intValue() + 1);
Now what do you suppose you'll get? "x is 1" is what you'll get, because all you did in the addOne() method was reassign a copy of your original reference "x". Of course, when working with mutable objects (Integer is immutable), it gets confusing to those who don't understand as you can operate on the actual object because you have a copy of its address in your copied reference. However Java is and remains pass-by-value only. To insist otherwise just muddies the waters and confuses those who are not clear.
Why would you think this proves your point? You aren't doing anything to the passed-in reference. You don't even call this addOne function! Is there code missing here? I'm not a JavaLanguage programmer and I'm not familiar with the intricate details of it's passing model, but the fact that it's technically pass by value doesn't mean that it's not semantically pass by reference. A CeeLanguage function that you pass a pointer to is generally considered to be using pass by reference, although in actual fact you're passing (a pointer) by value.
I think the key to why Java developers tend to favor calling Java pass-by-value only is that it creates a much simpler basis for understanding the language and understanding programming in general, really. It similar to the difference between explaining the apparent motion of the Sun from a geocentric view versus a heliocentric view. The geocentric view may be more easily understood on a superficial level but giving exact predictions using that framework requires creating complicated and seemingly arbitrary rules. Likewise, calling Java pass-by-reference for Objects may seem less complicated at first but in order to explain why certain things do not work as expected requires some arbitrary rules and confusing explanations. Describing the apparent motion of the Sun from a heliocentric stance may be less obvious but is clearly a superior system because the rules are consistent and logical. Likewise, explaining that Java is pass-by-value may cause a new developer to be puzzled at first but once that hurdle is cleared, the foundation for understanding other important Java features such as garbage collection is laid.
On a final note, just like we still speak of the sun setting and rising, Java developers do not rigidly hold to the pass-by-value definition in casual discussion with other experienced developers. The pass-by-value explanation is mainly for newcomers to the language. Once a developer is familiar with the parameter passing mechanism, Java developers tend to speak in terms of pass-by-value semantics either explicitly or implicitly.
-James Watson (dubwai)
Java passes pointers
to objects by value; which is equivalent to passing the objects themselves by reference. Unlike C++, Java does not allow "direct" manipulation of objects--a stack frame (or an object) can only hold pointers
to other objects, never copies.
Java passes intrinsic values (ints, booleans) by value--but as these things are immutable; there is no semantic difference between CallByValue
in the latter case.
I find it odd word play to suggest that Java is pass-by-value because in actuality it is passing object references
by value. To prove it, I will ask a question which demonstrates this dissonance: Will you find me a pass-by-reference language in which the implementation does not pass its references by value?
If we accept this definition of pass-by-value, we have now have a zero-sized set of pass-by-reference languages. Unless there are some that use three levels of indirection to pass parameters, but I have not encountered any. And I can't imagine the functional benefits of such a thing.
See top of page discussion of inability to write a "swap" function in Java, whereas it is
possible in e.g. a C++ function that uses the optional pass-by-reference. That's a definitive touchstone. The "odd word play" is in your imagination.
Feel free to read pages before commenting. :-P
I read the page (as Jason no doubt did) and I got to the bottom with the same question. Above, there is an assertion that "you cannot directly write a swap function" but no explanation as to why. I jumped off to one of the off-wiki references, and found "Cat A = new Cat();Cat B = A; ... You can change the object A refers to, but you can't take the A reference variable and do something to it -- like redirect it to reference a different object, or null." (http://www.javaranch.com/campfire/StoryPassBy.jsp) Maybe that helps answer the question: or maybe this page should be JavaPassesByValueNotBySymbol??
What if we compromise?
. However, it passes references
When we teach the young new programmers, we can explain it as follows:
Java passes everything by value. However, objects are manipulated
by reference. That means, you can never actually get at the 'actual' objects, just the references. Java passes references, but it doesn't pass by
reference. Clear? No? OK...
And then, we'll give some examples, and maybe a remote control analogy.
Just in case anyone tries the above example using "Integer", and you don't get the expected result, you aren't crazy. Integer gets autoboxed to an int meaning you are no longer passing a reference by value, you really are passing a value.
See also ParameterPassing