I'm going to explain this through byte code. First thing to note is that while a reachable reference exists to an object, that object cannot be collected. A important aspect of this is that if a reference value is on the stack in a method's stack frame, the object being referenced is accessible. It therefore cannot be garbage collected.
Compile the following program
public class Example {
public static void main(String[]args) {
new Example().sayHello();
}
public void sayHello() {}
}
Running javap -c Example will give you something like
public static void main(java.lang.String[]);
Code:
stack=2, locals=1, args_size=1
0: new #2 // class Example
3: dup
4: invokespecial #3 // Method "<init>":()V
7: invokevirtual #4 // Method sayHello:()V
10: return
A index 0, the new byte code instruction, creates a new object and pushes the reference to that object onto the stack. The dup instruction copies that value and pushes it on top of the stack. So you now have two references to that object. invokespecial uses one, invokevirtual uses the other (they pop the reference value they use). Once that is done, there are no more references to the object and it can be garbage collected.
For reference, here are the byte code instructions.
(new TestObject()).dosomething();there is a reference to TestObject very briefly in the Java stack, and then it goes away, either because the stack entry is reused or because the method returns. Once it's gone the object can be collected.new TestObject();by itself, so that the object never has a reference variable pointing at it, and it will still be collected.)