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


I always thought Java was pass-by-reference; however I've seen a couple of blog posts (For example, this blog) that claim it's not. I don't think I understand the distinction they're making.

What is the explanation?




Answers


Java is always pass-by-value. Unfortunately, they decided to call the location of an object a "reference". When we pass the value of an object, we are passing the reference to it. This is confusing to beginners.

It goes like this:

public static void main( String[] args ) {
    Dog aDog = new Dog("Max");
    // 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, java passes by value
    aDog.getName().equals("Fifi"); // false 
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // change d inside of foo() to point to a new Dog instance "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 with the Dog "Fifi" as the object reference is passed by value. If it were 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");
    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // 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 the above example, FiFi is the 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 itself (except when d is changed to point to a different Dog instance like d = new Dog("Boxer")).




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.

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 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, you cannot change where that pointer points.

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.




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:

  1. Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".

    Foo f = new Foo("f");

  2. From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.

    public static void changeReference(Foo a)

  3. As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.

    changeReference(f);

  4. Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".

    Foo b = new Foo("b");

  5. a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".


  6. As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".

  7. c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.

I hope you understand now how passing objects as arguments works in Java :)




Are arrays passed by value or passed by reference in Java?

Technically, it is passed by value ... but the value is the reference to the array.

Real passing by reference involves passing the address of a variable so that the variable can be updated. This is NOT what happens when you pass an array in Java.

Here are some links that explain the difference between "pass-by-reference" and "pass-by-value":

Related SO question:

Historical background:

The phrase "pass-by-reference" was originally "call-by-reference", and it was used to distinguish the argument passing semantics of FORTRAN (call-by-reference) from those of ALGOL-60 (call-by-value and call-by-name).

  • In call-by-value, the argument expression is evaluated to a value, and that value is copied to the called method.

  • In call-by-reference, the argument expression is partially evaluated to an "lvalue" (i.e. the address of a variable or array element) that is passed to the calling method. The calling method can then directly read and update the variable / element.

  • In call-by-name, the actual argument expression is passed to the calling method (!!) which can evaluate it multiple times (!!!). This was complicated to implement, and could be used (abused) to write code that was very difficult to understand. Call-by-name was only ever used in Algol-60 (thankfully!).

UPDATE

Actually, Algol-60's call-by-name is similar to passing lambda expressions as parameters. The wrinkle is that these not-exactly-lambda-expressions (they were referred to as "thunks" at the implementation level) can indirectly modify the state of variables that are in scope in the calling procedure / function. That is what made them so hard to understand. (See the Wikipedia page on Jensen's Device for example.)




Everything in Java are passed-by value.. In case of Array(Which is nothing but an Object), array reference is passed by value.. (Just like an object reference is passed by value)..

When you pass an array to other method, actually the reference to that array is copied..

  • Any changes in the content of array through that reference will affect the original array..
  • But changing the reference to point to a new array will not change the existing reference in original method..

See this post..

Is Java "pass-by-reference" or "pass-by-value"?

See this working example: -

public static void changeContent(int[] arr) {

   // If we change the content of arr.
   arr[0] = 10;  // Will change the content of array in main()
}

public static void changeRef(int[] arr) {
   // If we change the reference
   arr = new int[2];  // Will not change the array in main()
   arr[0] = 15;
}

public static void main(String[] args) {
    int [] arr = new int[2];
    arr[0] = 4;
    arr[1] = 5;

    changeContent(arr);

    System.out.println(arr[0]);  // Will print 10.. 

    changeRef(arr);

    System.out.println(arr[0]);  // Will still print 10.. 
                                 // Change the reference doesn't reflect change here..
}



Arrays are in fact objects, so a reference is passed (the reference itself is passed by value, confused yet?). Quick example:

// assuming you allocated the list
public void addItem(Integer[] list, int item) {
    list[1] = item;
}

You will see the changes to the list from the calling code. However you can't change the reference itself, since it's passed by value:

// assuming you allocated the list
public void changeArray(Integer[] list) {
    list = null;
}

If you pass a non-null list, it won't be null by the time the method returns.




Java is NEVER pass-by-reference, right?…right?

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.




The references themselves are passed by value.

From Java How to Program, 4th Edition by Deitel & Deitel: (pg. 329)

Unlike other languages, Java does not allow the programmer to choose whether to pass each argument by value or by reference. Primitive data type variables are always passed by value. Objects are not passed to methods; rather, references to objects are passed to methods. The references themselves are passed by value—a copy of a reference is passed to a method. When a method receives a reference to an object, the method can manipulate the object directly.

Used this book when learning Java in college. Brilliant reference.

Here's a good article explaining it. http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html




Is Java really passing objects by value?

Java always passes arguments by value, NOT by reference. In your example, you are still passing obj by its value, not the reference itself. Inside your method changeName, you are assigning another (local) reference, obj, to the same object you passed it as an argument. Once you modify that reference, you are modifying the original reference, obj, which is passed as an argument.


EDIT:

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 change the object that the reference 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:

1- Declaring a reference named f of type Foo and assign it to a new object of type Foo with an attribute "f".

Foo f = new Foo("f");

2- From the method side, a reference of type Foo with a name a is declared and it's initially assigned to null.

public static void changeReference(Foo a)

3- As you call the method changeReference, the reference a will be assigned to the object which is passed as an argument.

changeReference(f);

4- Declaring a reference named b of type Foo and assign it to a new object of type Foo with an attribute "b".

Foo b = new Foo("b");

5- a = b is re-assigning the reference a NOT f to the object whose its attribute is "b".


6- As you call modifyReference(Foo c) method, a reference c is created and assigned to the object with attribute "f".

7- c.setAttribute("c"); will change the attribute of the object that reference c points to it, and it's same object that reference f points to it.

I hope you understand now how passing objects as arguments works in Java :)




In Java, an object handle, or the identity of an object is considered a value. Passing by value means passing this handle, not a full copy of the object.

A "reference" in the term "pass by reference" also doesn't mean "reference to an object". It means "reference to a variable" – a named "bucket" in a function definition (or, rather, a call frame) that can store a value.

Passing by reference would mean the called method could change variable values in the calling method. (For example, in the C standard library, the function scanf works this way.) This isn't possible in Java. You can always change the properties of an object – they aren't considered a part of its "value". They're completely different independent objects.




You're changing a property of obj, not changing obj (the parameter) itself.

The point is that if you pointed obj at something else in changeName that that change would not be reflected in main.

See this post for further clarification.