6

Suppose I have a class and constructor called TestClass.

public class TestClass {
    Foo foo;

    public TestClass(Foo foo) {
        this.foo = foo; 
    }
}

Here, the constructor accepts an object which is an instance of class Foo. Suppose my static void main(String[] args) does the following, completely separate from any TestClass;

  • (1) Instantiate foo

  • (2) Pass instance foo to TestClass constructor

  • (3) Change the internal state of foo

After step (3), will the foo within my instance of TestClass also have its state changed?

user2763361
  • 3,789
  • 11
  • 45
  • 81
  • 2
    You could also write a little program to see for yourself, though I'll concede that *why* this occurs isn't necessarily something you can learn just by trying small examples. – Dennis Meng Oct 21 '13 at 02:39
  • 2
    @DennisMeng This is true, but doing this myself will not reveal any edge cases that an experienced answerer can cover. – user2763361 Oct 21 '13 at 02:39
  • to answer your title, Java does not have pass by reference. It passes a reference by value though, and that is causing the problem you are seeing. – Karthik T Oct 21 '13 at 02:40

3 Answers3

16

It is not passed by reference. Rather, it is passed by value of the reference, which is a subtle but important distinction.

After you mutate foo in the rest of your main() method, the foo field will also exhibit these mutations, as you state, since both variables point to the same instance. However, if you reassign foo to something new, the foo field will not be changed. This would not be true if foo were truly passed by reference. In short, everything is passed by value in Java; it just so happens that objects are dealt with by reference, and so the values of these references are passed.

I'll try to illustrate this with an example. Consider the following class:

class A {
    public int n;

    public A(int n) {
        this.n = n;
    }
}

and the following method:

public static void mutate(A a) {
    a.n = 42;
}

Now we can have something like this:

A a = new A(0);
A.mutate(a);

System.out.println(a.n);
42

We can see that the state of a was changed in mutate(). Now let's modify the static method:

public static void mutate(A a) {
    a = new A(42);
}

and try again:

A a = new A(0);
A.mutate(a);

System.out.println(a.n);
0

As you can see, the state of a is unchanged. If the reference had been passed to the function, we would expect the effect of the reassignment to be evident beyond the scope of the method. Nevertheless, some reference was in fact passed, since mutating the argument caused changes outside of the method as well.

arshajii
  • 127,459
  • 24
  • 238
  • 287
3

enter image description hereYes, because you are assigning same object to another reference of Foo class, i.e. object is same, but being referred by two reference.

codingenious
  • 8,385
  • 12
  • 60
  • 90
1

After step (3), will the foo within my instance of TestClass also have its state changed?

Yes.

You might like to take a read through this

Updated...

Now, assuming you pass the constructor a primitive value...

public class TestClass {
    int foo;

    public TestClass(int foo) {
        this.foo = foo; 
    }

    public String toString() {
        return "TestClass: " + foo;
    }
}

public static void main(String args[]) {
    int myFoo = 1;
    TestClass test = new TestClass(myFoo);
    myFoo += 2;
    System.out.println("myFoo = " + myFoo);
    System.out.println("yourFoo = " + test);
}

This will output...

myFoo = 3
yourFoo = 1

Which demonstrates the fact that changing the value of a primitive does not change the value maintained by the constructor/method.

Equally, if you change the object reference after you pass it

public class TestClass {
    Foo foo;

    public TestClass(Foo foo) {
        this.foo = foo; 
    }

    public Foo getFoo() {
        return foo;
    }
}

public static void main(String args[]) {
    Foo myFoo = new Foo();
    TestClass test = new TestClass(myFoo);
    myFoo = new Foo();
    System.out.println("myFoo == yourFoo = " + myFoo.equals(test.getFoo()));
}

Will output

myFoo == yourFoo = false

As the object references are not the same.

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • It's worth noting that if you have a primitive type, instead of an object type (for example, `int` instead of `Foo`), then the answer turns out to be _no_. – Dawood ibn Kareem Oct 21 '13 at 02:42
  • @DavidWallace Certainly not going to argue with that, but that would be the same as saying "if you created a new instance of `Foo` after passing it the constructor, wouldn't change the internal state of `Foo` within `TestClass`, but that's not the question...as I read it anyway...all this just makes my head swim :P – MadProgrammer Oct 21 '13 at 02:48
  • Sure. Not arguing there. I was just thinking about OP's comment about edge cases, and wondering whether "primitives" would be included in that category. Without that comment, this really is a yes/no question. – Dawood ibn Kareem Oct 21 '13 at 03:06
  • @DavidWallace That's actually a fair comment – MadProgrammer Oct 21 '13 at 03:08