Is Java "pass-by-reference" or "pass-by-value"?
Solution 1
The terms "pass-by-value" and "pass-by-reference" have special, precisely defined meanings in computer science. These meanings differ from the intuition many people have when first hearing the terms. Much of the confusion in this discussion seems to come from this fact.
The terms "pass-by-value" and "pass-by-reference" are talking about variables. Pass-by-value means that the value of a variable is passed to a function/method. Pass-by-reference means that a reference to that variable is passed to the function. The latter gives the function a way to change the contents of the variable.
By those definitions, Java is always pass-by-value. Unfortunately, when we deal with variables holding objects we are really dealing with object-handles called references which are passed-by-value as well. This terminology and semantics easily confuse many beginners.
It goes like this:
public static void main(String[] args) { Dog aDog = new Dog("Max"); Dog oldDog = aDog;
// we pass the object to foo foo(aDog); // aDog variable is still pointing to the "Max" dog when foo(...) returns aDog.getName().equals("Max"); // true aDog.getName().equals("Fifi"); // false aDog == oldDog; // true
}
public static void foo(Dog d) { d.getName().equals(“Max”); // true // change d inside of foo() to point to a new Dog instance construct red with name member variable set to “Fifi” d = new Dog(“Fifi”); d.getName().equals(“Fifi”); // true }
In this example, aDog.getName()
will still return "Max"
. The value aDog
within main
is not changed in the function foo
by creating new Dog
with name member variable set to "Fifi"
because the object reference is passed by value. If the object reference was passed by reference, then the aDog.getName()
in main
would return "Fifi"
after the call to foo
.
Likewise:
public static void main(String[] args) { Dog aDog = new Dog("Max"); Dog oldDog = aDog;
foo(aDog); // when foo(...) returns, the name of the dog has been changed to "Fifi" aDog.getName().equals("Fifi"); // true // but it is still the same dog: aDog == oldDog; // true
}
public static void foo(Dog d) { d.getName().equals(“Max”); // true // this changes the name of d to be “Fifi” d.setName(“Fifi”); }
In this example, Fifi
is dog’s name after call to foo(aDog)
because the object's name was set inside of foo(...)
. Any operations that foo
performs on d
are such that, for all practical purposes, they are performed on aDog
, but it is not possible to change the value of the variable aDog
itself.
For more information on pass by reference and pass by value, consult the following answer: https://stackoverflow.com/a/430958/6005228. This explains more thoroughly the semantics and history behind the two and also explains why Java and many other modern languages appear to do both in certain cases.
Solution 2
I just noticed you referenced my article.
The Java Spec says that everything in Java is pass-by-value. There is no such thing as "pass-by-reference" in Java.
The key to understanding this is that something like
Dog myDog;
is not a Dog; it's actually a pointer to a Dog. The use of the term "reference" in Java is very misleading and is what causes most of the confusion here. What they call "references" act/feel more like what we'd call "pointers" in most other languages.
What that means, is when you have
Dog myDog = new Dog("Rover");
foo(myDog);
you're essentially passing the address of the created Dog
object to the foo
method.
(I say essentially because Java pointers/references aren't direct addresses, but it's easiest to think of them that way.)
Suppose the Dog
object resides at memory address 42. This means we pass 42 to the method.
if the Method were defined as
public void foo(Dog someDog) {
someDog.setName("Max"); // AAA
someDog = new Dog("Fifi"); // BBB
someDog.setName("Rowlf"); // CCC
}
let's look at what's happening.
- the parameter
someDog
is set to the value 42 - at line "AAA"
someDog
is followed to theDog
it points to (theDog
object at address 42)- that
Dog
(the one at address 42) is asked to change his name to Max
- at line "BBB"
- a new
Dog
is created. Let's say he's at address 74 - we assign the parameter
someDog
to 74
- a new
- at line "CCC"
- someDog is followed to the
Dog
it points to (theDog
object at address 74) - that
Dog
(the one at address 74) is asked to change his name to Rowlf
- someDog is followed to the
- then, we return
Now let's think about what happens outside the method:
Did myDog
change?
There's the key.
Keeping in mind that myDog
is a pointer, and not an actual Dog
, the answer is NO. myDog
still has the value 42; it's still pointing to the original Dog
(but note that because of line "AAA", its name is now "Max" - still the same Dog; myDog
's value has not changed.)
It's perfectly valid to follow an address and change what's at the end of it; that does not change the variable, however.
Java works exactly like C. You can assign a pointer, pass the pointer to a method, follow the pointer in the method and change the data that was pointed to. However, the caller will not see any changes you make to where that pointer points. (In a language with pass-by-reference semantics, the method function can change the pointer and the caller will see that change.)
In C++, Ada, Pascal and other languages that support pass-by-reference, you can actually change the variable that was passed.
If Java had pass-by-reference semantics, the foo
method we defined above would have changed where myDog
was pointing when it assigned someDog
on line BBB.
Think of reference parameters as being aliases for the variable passed in. When that alias is assigned, so is the variable that was passed in.
Update
A discussion in the comments warrants some clarification...
In C, you can write
void swap(int *x, int *y) { int t = *x; *x = *y; *y = t; }
int x = 1; int y = 2; swap(&x, &y);
This is not a special case in C. Both languages use pass-by-value semantics. Here the call site is creating additional data structure to assist the function to access and manipulate data.
The function is being passed pointers to data, and follows those pointers to access and modify that data.
A similar approach in Java, where the caller sets up assisting structure, might be:
void swap(int[] x, int[] y) { int temp = x[0]; x[0] = y[0]; y[0] = temp; }
int[] x = {1}; int[] y = {2}; swap(x, y);
(or if you wanted both examples to demonstrate features the other language doesn't have, create a mutable IntWrapper class to use in place of the arrays)
In these cases, both C and Java are simulating pass-by-reference. They're still both passing values (pointers to ints or arrays), and following those pointers inside the called function to manipulate the data.
Pass-by-reference is all about the function declaration/definition, and how it handles its parameters. Reference semantics apply to every call to that function, and the call site only needs to pass variables, no additional data structure.
These simulations require the call site and the function to cooperate. No doubt it's useful, but it's still pass-by-value.
Solution 3
Java always passes arguments by value, NOT by reference.
Let me explain this through an example:
public class Main {
public static void main(String[] args) { Foo f = new Foo("f"); changeReference(f); // It won't change the reference! modifyReference(f); // It will modify the object that the reference variable "f" refers to! } public static void changeReference(Foo a) { Foo b = new Foo("b"); a = b; } public static void modifyReference(Foo c) { c.setAttribute("c"); }
}
I will explain this in steps:
Declaring a reference named
f
of typeFoo
and assign it a new object of typeFoo
with an attribute"f"
.Foo f = new Foo("f");
From the method side, a reference of type
Foo
with a namea
is declared and it's initially assignednull
.public static void changeReference(Foo a)
As you call the method
changeReference
, the referencea
will be assigned the object which is passed as an argument.changeReference(f);
Declaring a reference named
b
of typeFoo
and assign it a new object of typeFoo
with an attribute"b"
.Foo b = new Foo("b");
a = b
makes a new assignment to the referencea
, notf
, of the object whose attribute is"b"
.As you call
modifyReference(Foo c)
method, a referencec
is created and assigned the object with attribute"f"
.c.setAttribute("c");
will change the attribute of the object that referencec
points to it, and it's the same object that referencef
points to it.
Solution 4
Java is always pass by value, with no exceptions, ever.
So how is it that anyone can be at all confused by this, and believe that Java is pass by reference, or think they have an example of Java acting as pass by reference? The key point is that Java never provides direct access to the values of objects themselves, in any circumstances. The only access to objects is through a reference to that object. Because Java objects are always accessed through a reference, rather than directly, it is common to talk about fields and variables and method arguments as being objects, when pedantically they are only references to objects. The confusion stems from this (strictly speaking, incorrect) change in nomenclature.
So, when calling a method
- For primitive arguments (
int
,long
, etc.), the pass by value is the actual value of the primitive (for example, 3). - For objects, the pass by value is the value of the reference to the object.
So if you have doSomething(foo)
and public void doSomething(Foo foo) { .. }
the two Foos have copied references that point to the same objects.
Naturally, passing by value a reference to an object looks very much like (and is indistinguishable in practice from) passing an object by reference.
Solution 5
This will give you some insights of how Java really works to the point that in your next discussion about Java passing by reference or passing by value you'll just smile :-)
Step one please erase from your mind that word that starts with 'p' "_ _ _ _ _ _ _", especially if you come from other programming languages. Java and 'p' cannot be written in the same book, forum, or even txt.
Step two remember that when you pass an Object into a method you're passing the Object reference and not the Object itself.
- Student: Master, does this mean that Java is pass-by-reference?
- Master: Grasshopper, No.
Now think of what an Object's reference/variable does/is:
- A variable holds the bits that tell the JVM how to get to the referenced Object in memory (Heap).
- When passing arguments to a method you ARE NOT passing the reference variable, but a copy of the bits in the reference variable. Something like this: 3bad086a. 3bad086a represents a way to get to the passed object.
- So you're just passing 3bad086a that it's the value of the reference.
- You're passing the value of the reference and not the reference itself (and not the object).
- This value is actually COPIED and given to the method.
In the following (please don't try to compile/execute this...):
1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7. anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }
What happens?
- The variable person is created in line #1 and it's null at the beginning.
- A new Person Object is created in line #2, stored in memory, and the variable person is given the reference to the Person object. That is, its address. Let's say 3bad086a.
- The variable person holding the address of the Object is passed to the function in line #3.
- In line #4 you can listen to the sound of silence
- Check the comment on line #5
- A method local variable -anotherReferenceToTheSamePersonObject- is created and then comes the magic in line #6:
- The variable/reference person is copied bit-by-bit and passed to anotherReferenceToTheSamePersonObject inside the function.
- No new instances of Person are created.
- Both "person" and "anotherReferenceToTheSamePersonObject" hold the same value of 3bad086a.
- Don't try this but person==anotherReferenceToTheSamePersonObject would be true.
- Both variables have IDENTICAL COPIES of the reference and they both refer to the same Person Object, the SAME Object on the Heap and NOT A COPY.
A picture is worth a thousand words:
Note that the anotherReferenceToTheSamePersonObject arrows is directed towards the Object and not towards the variable person!
If you didn't get it then just trust me and remember that it's better to say that Java is pass by value. Well, pass by reference value. Oh well, even better is pass-by-copy-of-the-variable-value! ;)
Now feel free to hate me but note that given this there is no difference between passing primitive data types and Objects when talking about method arguments.
You always pass a copy of the bits of the value of the reference!
- If it's a primitive data type these bits will contain the value of the primitive data type itself.
- If it's an Object the bits will contain the value of the address that tells the JVM how to get to the Object.
Java is pass-by-value because inside a method you can modify the referenced Object as much as you want but no matter how hard you try you'll never be able to modify the passed variable that will keep referencing (not p _ _ _ _ _ _ _) the same Object no matter what!
The changeName function above will never be able to modify the actual content (the bit values) of the passed reference. In other word changeName cannot make Person person refer to another Object.
Of course you can cut it short and just say that Java is pass-by-value!