You can notice what happens underneath by simply decompiling the inner class. Here is a short example:
After compiling this piece of code:
public class Test {
public void method() {
final Object handle = new Object();
Thread thread = new Thread() {
public void run() {
handle.toString();
}
};
thread.start();
}
}
you will get Test.class for Test.java and Test$1.class for the inner class in Test.java. After decompiling the Test$1.class you will see this:
class Test$1 extends Thread
{
final Test this$0;
private final Object val$handle;
public void run()
{
this.val$handle.toString();
}
}
As you can see instead of handle variable there is this.val$handle. This means that handle is copied as a val$handle field to the inner class. And this will work correctly only if the handle will never change - which in Java means it must be final.
You can also notice that the inner class has a field this$0 which is a reference to the outer class. This in turn shows how non static inner classes are able to communicate with outer classes.