Java 当方法中有最终值和内部类时,会发生什么?

Java 当方法中有最终值和内部类时,会发生什么?,java,inner-classes,Java,Inner Classes,我遇到过很多情况,我需要将值传递给另一个线程,我发现我可以这样做,但我一直想知道它是如何工作的 public void method() { final EventHandler handle = someReference; Thread thread = new Thread() { public void run() { handle.onEvent(); } }; thread.start();

我遇到过很多情况,我需要将值传递给另一个线程,我发现我可以这样做,但我一直想知道它是如何工作的

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

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

    thread.start();
}

编辑:要知道我的问题并没有完全指向我想知道的东西。与其说是“为什么”,不如说是“如何”。没有任何方法可以访问其他方法的局部变量。这包括匿名类的方法,如示例中所示。也就是说,匿名线程类中的
run
方法无法访问
method()
的局部变量


在局部变量前面写入
final
,对于程序员来说是一种让编译器知道变量实际上可以作为值处理的方法。由于此变量(读取值!)不会更改,因此可以通过其他方法访问它。

下面是对其工作原理的详细解释:

此内部类被转换为类似于以下内容的代码:

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();

由于内部类实际上获得了最终变量的副本,因此它不能对其进行任何在外部类中可见的更改。要禁止甚至尝试更改此参数,只允许访问内部类中的最终变量。

只需对内部类进行反编译,就可以看到下面发生了什么。下面是一个简短的例子:

编译完这段代码后:

public class Test {

 public void method() {
     final Object handle = new Object();

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

     thread.start();
 }
}
对于
Test.java
您将获得
Test.class
,对于
Test.java
中的内部类,您将获得
Test.class
。反编译
测试$1.class
后,您将看到:

class Test$1 extends Thread
{
  final Test this$0;
  private final Object val$handle;

  public void run()
  {
    this.val$handle.toString();
  }
}
正如您所看到的,这里没有
handle
变量,而是
这个.val$handle
。这意味着
handle
作为
val$handle
字段复制到内部类。只有当
句柄
永远不会改变时,这才能正常工作——在Java中,这意味着它必须是
最终的

您还可以注意到,内部类有一个字段
this$0
,它是对外部类的引用。这反过来说明了非静态内部类如何能够与外部类通信