Every I object has two members, a reference to a
String which represents its name and a reference to another I object, named other.
When we initialize J, we create 3 new objects, like this:
In this case, the letter represents the name, the null represents the value of the member variable other for each I object.
Now, when we invoke the method m1, we start invoking the other method of our I objects. Executing this line of code:
causes the method I.other to be invoked. So, if we follow the execution to that method, we see this code:
This line simply assigns the value of i, which, in this case, is a reference to the object referenced by i2 (that's the I object named B), to the member variable other. So, now our picture has changed slightly - it now looks like this:
As you can see from the picture, the object named A now contains a reference to the object named B.
The next two invocations of the method m1 perform a similar function, just on different objects. Once they're done, our picture looks like this:
The objects named A and B have references to each other and object C contains a reference to itself.
Now that we're done invoking the m1 method, we can go on to the next lines of code, that do this:
These lines simply reassign i1 and i2 to reference the same object that i3 references. Again, our picture changes to look like this:
Now, you can see that i1, i2, and i3 all reference the same object and the only things that reference objects A and B are each other. As those objects can no longer be accessed via an active part of the application, they can be safely garbage collected. Object C, on the other hand, can still be accessed via the member variables i1, i2, or i3, so that object is not eligible for garbage collection.
I hope that helps,
Corey