Is Java “pass-by-reference” or “pass-by-value”?

I always thought Java uses pass-by-reference. However, I read a blog post which claims that Java uses pass-by-value. I don’t think I understand the distinction the author is making.

What is the explanation?

  • 8

    We would more commonly say that a variable “passed-by-reference” can be mutated. The term appears in textbooks because language theorists needed a way to distinguish how you treat primitive data types (int, bool, byte) from complex and structured objects (array, streams, class) — that is to say, those of possibly unbounded memory allocation.

    – 

  • 7

    I want to note that you do not have to think about this in most cases. I programmed java for many years until i learned c++. Until this point in time i had no clue what pass-by-reference and pass-by-value are. The intuitive solution always worked for me, which is why java is one of the best languages for beginners. So if you currently are worried, if your function needs a reference or a value, just pass it as it is and you will be fine.

    – 

  • 24

    Putting it very concisely, this confusion arises because in Java all non-primitive data types are handled/accessed by references. However, passing is always be value. So for all non-primitive types reference is passed by its value. All primitive types are also passed by value.

    – 

  • 6

    I found this quite helpful: baeldung.com/java-pass-by-value-or-pass-by-reference

    – 

  • 5

    Before you post a new answer, consider there are already 93+ answers to this question. Please ensure that your answer contributes information that is not among existing answers. Thanks!

    – 

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 the Dog it points to (the Dog 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
  • at line “CCC”
    • someDog is followed to the Dog it points to (the Dog object at address 74)
    • that Dog (the one at address 74) is asked to change his name to Rowlf
  • 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.

Leave a Comment