methods – Is Java pass-by-reference or pass-by-value?

methods – Is Java pass-by-reference or pass-by-value?

Java is always pass-by-value. Unfortunately, when we deal with 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 Fifi
    d = new Dog(Fifi);
    d.getName().equals(Fifi); // true
}

In the example above 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);
    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 the above example, Fifi is the dogs name after call to foo(aDog) because the objects 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 SO 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 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; its 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 wed call pointers in most other languages.

What that means, is when you have

Dog myDog = new Dog(Rover);
foo(myDog);

youre essentially passing the address of the created Dog object to the foo method.

(I say essentially because Java pointers/references arent direct addresses, but its 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
}

lets look at whats 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. Lets say hes 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 lets think about what happens outside the method:

Did myDog change?

Theres 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; its still pointing to the original Dog (but note that because of line AAA, its name is now Max – still the same Dog; myDogs value has not changed.)

Its perfectly valid to follow an address and change whats 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.

methods – Is Java pass-by-reference or pass-by-value?

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 wont 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 a new object of type Foo with an attribute f.

    Foo f = new Foo(f);
    

    enter

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

    public static void changeReference(Foo a)
    

    enter

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

    changeReference(f);
    

    enter

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

    Foo b = new Foo(b);
    

    enter

  5. a = b makes a new assignment to the reference a, not f, of the object whose attribute is b.

    enter

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

    enter

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

    enter

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

Leave a Reply

Your email address will not be published. Required fields are marked *