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.
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.
I'm the author of the blog post you're talking about. To clarify a few things:
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
someDogis set to the value 42 - at line "AAA"
someDogis followed to theDogit points to (theDogobject at address 42)- that
Dog(the one at address 42) is asked to change his name to Max
- at line "BBB"
- a new
Dogis created. Let's say he's at address 74 - we assign the parameter
someDogto 74
- a new
- at line "CCC"
- someDog is followed to the
Dogit points to (theDogobject 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.
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.
In c#, you can use the keyword ref to pass a primitive by reference, which sometimes comes in handy. Why does java not have this? It forces you to either use a hack (like 1 length array), refactor code, or return multiple values via your own Tuple class.
reason: why java is not pass by reference? - Stack Overflow
Can someone explain pass by value in Java please?
Why doesn't java support pass by reference like C++ - Stack Overflow
Java is NEVER pass-by-reference, right?...right? - Stack Overflow
Videos
I've read multiple explanations online but I'm still having trouble understanding. I understand that Java is pass by value but from what I understand objects are passed by reference. My programming teacher even had trouble explaining this. Can someone please give me a clear explanation of this, in layman's terms, as if I had never programmed before?
Also, if someone could give some of the pros and cons of pass by value and pass by reference that would be great too, and what languages are pass by value and which are pass by reference?
By design:
Some people will say incorrectly that objects are passed "by reference." In programming language design, 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.... The Java programming language does not pass objects by reference; it passes object references by value. Because two copies of the same reference refer to the same actual object, changes made through one reference variable are visible through the other. There is exactly one parameter passing mode -- pass by value -- and that helps keep things simple. -- James Gosling, et al., The Java Programming Language, 4th Edition
As for deeper reasons, here's my take: it's the combination of two facts:
- The last line of the Gosling citation: "...that helps keep things simple..."
- Unlike C++, Java is garbage collected with all objects allocated on the heap.
I can't help it if you don't like the first one. You'll have to tell James Gosling and Bill Joy and all the other folks who designed Java that they made a critical error. Good luck with that. Java is far more widely used than C++ today by several measures. The marketplace, however imperfect, has not penalized Java for what you perceive as an oversight.
Pass by value in C++ places burdens on both the developer (e.g. requirement of assignment and copy constructors) and the compiler writer (e.g. differentiating between stack and heap variables, all permutations of pass by value and reference with const and non-const).
The second one might have more of a technical explanation besides the designers' taste. I'm not an expert in the design and implementation of garbage collected systems, but perhaps that influenced their choice for a technical reason that I don't know.
My understanding is that the reason for not having pass-by-reference is mostly for security reasons: passing things by reference would enable a function to change stuff that is outside its scope and that means that my object (reference) may be replaced if I call a malicious function.
To elaborate: In Java, encapsulation is important and a safety measure. When giving a (pointer) to an object to a function that someone else wrote, I (as the caller) should be convinced that the function I call can only do with that object what I allowed it to do (using public members). Allowing a PBR would leave me (as the caller) in an unknown state after the function finished as I would not know if I am handling my own object or something else...
As Rytmis said, Java passes references by value. What this means is that you can legitimately call mutating methods on the parameters of a method, but you cannot reassign them and expect the value to propagate.
Example:
private void goodChangeDog(Dog dog) {
dog.setColor(Color.BLACK); // works as expected!
}
private void badChangeDog(Dog dog) {
dog = new StBernard(); // compiles, but has no effect outside the method
}
Edit: What this means in this case is that although voiceSetList might change as a result of this method (it could have a new element added to it), the changes to vsName will not be visible outside of the method. To prevent confusion, I often mark my method parameters final, which keeps them from being reassigned (accidentally or not) inside the method. This would keep the second example from compiling at all.
Java passes references by value, so you get a copy of the reference, but the referenced object is the same. Hence this method does modify the input list.
Java is pass by value. Think of it like a pointer language like C, the value of the pointer (memory address) is being passed, so you have a reference to the same object. Primitives aren't stored internally the same way as Objects, so when you pass a primitive's value, it's the content, not a pointer.
There is a test for whether a language is pass-by-reference: can you write a swap function, such that after swap(a,b), the caller finds that the values of a and b are reversed? You cannot do this in Java, not even for objects.
Note that you cannot achieve this goal by swapping the internals of the two objects - while the data may change, the identity of the objects has not, and this has consequences. For one thing, any other variable in the program that referenced either object would also see the change.
To see why you cannot write this swap, consider a simplified model of the language, in which the value of a reference variable is the address of the object it is currently bound to (garbage collection complicates this picture in a way not relevant here.) Before the call to swap, the caller's stack frame has a slot for a, containing the address of object A, and a slot for b containing the address of B. When swap is called, it receives the values of a and b, which are the addresses of A and B respectively. Therefore, it is decoupled from the caller: there is simply no way for it to find the addresses of the slots for a and b within the caller's stack frame, and therefore no way to set them so that the caller will see them swapped.
@supercat suggests an alternative way of looking at it: conceptually, a reference variable holds the unique ID of the object it references, something that is fixed for the life of the object, and it is this that gets copied to the function in a call. This view also makes it clear that the function has no way to find, let alone modify, the variable in the caller's stack frame.
Call-by-reference means exactly the opposite, by definition: the function accesses its arguments through the caller's variable bindings, so that changing one of its arguments' binding in the function necessarily changes it in the caller's stack frame. The term dates to a time when mainstream languages did not have objects or references as first-class entities, and when an argument was passed, either a copy of its value (in pass-by-value) or its address (in pass-by-reference) was pushed on to the stack so that the function could retrieve it. Passing an argument's address allows swap to work, but passing an address it contains does not.
Another way of looking at it: pass-by-reference does not mean pass the reference held in the argument variable, it means create, in the function, a local variable that references the argument variable.
Therefore, we can see that Java uses pass-by-value, not pass-by-reference.
See also Java is Pass-by-Value, Dammit! which also discusses argument-passing in Java RMI.
I've encountered experienced C and C++ developers who are convinced that Java is pass-by-reference for objects. One example I've used is this one:
void changeInt(int x){
x = 42;
}
void changeString(String x){
x = "hello world";
}
void testChanges(){
int i = 0;
changeInt(i);
System.out.println(i); // still 0
String s = "test";
changeString(s);
System.out.println(s); //still test
}
The changeInt() function fails to change the value of the parameter, because it's pass-by-value. But then the changeString() function also fails to change the value of the parameter- because it's also pass-by-value.
I also really like Cup Size -- a story about variables and its follow-up Pass-by-Value Please to explain the difference between pass-by-value and pass-by-reference from a Java perspective.
Now, as for whether you actually bring this up to your teacher, I'm not sure. If I were you I'd probably just bite my tongue and move on with my life.
In an introductory Java class, I think it's fine to say that primitives are passed by value and that objects are passed by reference. That tells students what they need to know, although I might phrase it differently. (I'd say that primitives and references are copied when they're passed.)
In an upper-division programming languages course, I'd go into more detail about calling conventions and the full story about pass-by-value and pass-by-reference (and pass-by-name, so I can tell the joke about Niklaus Wirth), if there's time.
While I love for students to catch my mistakes and white lies, I think it might be nitpicky to do so in this case. If you feel a need to bring it up, go to the professor's office hours and express confusion reconciling what he said with what you've read online (perhaps citing a specific source). If he's a decent professor, he'll admit to having oversimplified or he'll accept the new knowledge.
Update
After reading Kevin Workman's answer, I see the problem with using the term "call by reference". I agree that no good can come from misusing that term. My second and third paragraphs still stand.
I've currently got a year of Java under my belt, but after coming back from summer break which I did not code at all whatsoever, my brain is foggy.
I remember in C++ we would use things like & for reference or * pointer. In Java I don't really ever remember worrying about reference vs value, but today our professor brought it up and I embarrassingly got it wrong. The explanation was something like that the other method creates a copy of the variable so updating that copy doesn't update the original variable.
Then he talked about primitive types have this issue but if you create some other variable it won't happen? (Might have incorrectly paraphrased that)
As I said I am not drop dead dumb, I just really need a refresher. I kind of remember using this keyword and getters/setters to properly update the program, but yeah I am super foggy right now...