views:

146

answers:

4

I have came across many situation where I needed to pass value to an other thread and I founded out that I could do it this way, but I have been wondering how is it working ?

public void method() {
    final EventHandler handle = someReference;

    Thread thread = new Thread() {
        public void run() {
            handle.onEvent();
        }
    };

    thread.start();
}

Edit: Just realise my question wasn't exactly pointing toward what I wanted to know. It's more "how" it works rather then "why".

+7  A: 

No method can access local variables of other methods. This includes methods of anonymous classes as the one in your example. That is, the run method in the anonymous Thread class, can not access the local variable of method().

Writing final in front of the local variable is a way for you as a programmer to let the compiler know that the variable actually can be treated as a value. Since this variable (read value!) will not change, it is "ok" to access it in other methods.

aioobe
+8  A: 

Here's a longer explanation of HOW it works: http://techtracer.com/2008/04/14/mystery-of-accessibility-in-local-inner-classes/

cristis
+1  A: 

This inner class gets translated to code similar to:

class InnerClass extends Thread {
    private EventHandler handle;

    public InnerClass(EventHandler handle) {
        this.handle = handle;
    }

    public void run() {
        handle.onEvent();
    }
}

...

EventHandler handle = someReference;
Thread thread = new InnerClass(handle);
thread.start();

Since the inner class actually gets passed a copy of the final variable it can not make any changes to it that would be visible in the outer class. To disallow even trying to make changes to this parameter it is only allowed to acces final variables in inner classes.

Jörn Horstmann
+4  A: 

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.

Piotr