Java changes reference but not the object itself?

2019-07-24 20:30发布

问题:

Please see the following code:

public static void main(String[] args)
{
    Test t1 = new Test();
    t1.i = 1;
    Test t0 = t1;
    Test t2 = new Test();
    t2.i = 2;
    t0 = t2; 
    System.out.println(t1.i); //prints 1, I thought it would print 2
}

Is there any way to change t1 object after I got it from somewhere else by simple assignment without accessing t1 directly? (i.e. t1 = t0)

回答1:

Here is an illustration of your program and what it does. Each state of the system is shown separated by a dashed line.

Note what happens when you do t0 = t1. You assumed that this means that from now on, t0 and t1 are synonyms - whenever you use one, the other is affected. But in fact, t0 and t1 are simply two references to the same object.

Making a new assignment to t0 simply detached it from the "blue" object and re-attached it to the "violet" object.

As long as t0 and t1 were both pointing at the same object, any changes you make in the content of their pointed object (such as t0.i = 5) would be seen by the other reference, because they both refer to the same object. But as soon as you assign something else to t0, it loses its connection to t1. After you do that, changing it will be reflected in t2, which points to the same, "violet" object, not in t1 which still points to the old, "blue" one.

So:

  • If you assign a new value to the reference - it no longer points to the same object as before, and any previous "double referencing" is lost.
  • If you assign a new value to the content of the reference, it will be reflected in all reference variables that look at the same object.



回答2:

Test t1 = new Test();
t1.i = 1

can be represented as

            +-------+
            | Test  |
t1 -------> +-------+
            | i (1) |
            +-------+

now when you do

Test t0 = t1;

You are assigning to t0 same value as value from t1, which means that now they hold same value (address to same Test instance), so your situation is

            +-------+
t1 ----+    | Test  |
       +--> +-------+
t0 ----+    | i (1) |
            +-------+

Now after this code

Test t2 = new Test();
t2.i = 2;

you will have

            +-------+
t1 ----+    | Test  |
       +--> +-------+
t0 ----+    | i (1) |
            +-------+

            +-------+
            | Test  |
t2 -------> +-------+
            | i (2) |
            +-------+

and when you do

t0 = t2; 

you change your situation to

            +-------+
t1 ----+    | Test  |
       +--> +-------+
            | i (1) |
t0 ----+    +-------+
       |
       |    +-------+
       |    | Test  |
t2 ----+--> +-------+
            | i (2) |
            +-------+

so as you see now t0 holds same object as object held by t2 reference, but t1 reference wasn't changed, and that is why

System.out.println(t1.i)

prints 1.



回答3:

What you did not understand here is that when doing t0 = t2 you replace the adress reference of t0 which is at that time the same as t1 by the reference of t2 so no, it won't affect t1.

However, t0.i would print 2.

But to answer your question

Is there any way to change t1 object after I got it from somewhere else by simple assignment without accessing t1 directly? (i.e. t1 = t0)

Yes there is a way, check this snippet

Test t1 = new Test();
t1.i = 1;
Test t0 = t1;
t0.i = 3;
System.out.println(t1.i); //prints 3

This will modify t1.i to 3 accessing t0.i

If you want to do it using the t2 object, then you can modify the value of i directly :

Test t1 = new Test();
t1.i = 1;
Test t0 = t1;
Test t2 = new Test();
t2.i = 2;
t0.i = t2.i; 
System.out.println(t1.i); //prints 2