Java Passes By Value

From JavaLanguageSpecification:

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.

-- ChanningWalton, PhilGoodwin, WayneConrad

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.

Therefore JavaPassesByValue, 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.

Discussion:

Explanation:


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, PythonLanguage, SchemeLanguage, 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.

In CeeLanguage and PascalLanguage, 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):

Yes, it may look like JavaDoesntPassByValue, but now you can see why it's true that JavaPassesByValue.

-- MarkTaylor 02/15/2004


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 and CallByReference 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.

--JasonFelice

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?

JavaPassesByValue. However, it passes references by value.

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, JavaDoesntPassByValue, LanguageGotchas


EditText of this page (last edited November 13, 2014) or FindPage with title or text search