【问题标题】:What exactly happens when you have final values and inner classes in a method?当方法中有最终值和内部类时,究竟会发生什么?
【发布时间】:2010-06-26 20:22:37
【问题描述】:

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

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

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

    thread.start();
}

编辑:只要意识到我的问题并不完全指向我想知道的。更多的是“如何”工作,而不是“为什么”。

【问题讨论】:

    标签: java inner-classes


    【解决方案1】:

    【讨论】:

      【解决方案2】:

      没有方法可以访问其他方法的局部变量。这包括匿名类的方法,例如您的示例中的方法。即匿名Thread类中的run方法,无法访问method()的局部变量。

      在局部变量前面写final 是程序员让编译器知道变量实际上可以被视为值的一种方式。由于这个变量(读取值!)不会改变,所以在其他方法中访问它是“可以的”。

      【讨论】:

        【解决方案3】:

        您可以通过简单地反编译内部类来注意到下面发生的事情。这是一个简短的例子:

        编译这段代码后:

        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$1.class。反编译Test$1.class后你会看到:

        class Test$1 extends Thread
        {
          final Test this$0;
          private final Object val$handle;
        
          public void run()
          {
            this.val$handle.toString();
          }
        }
        

        如您所见,this.val$handle 不是变量handle。这意味着handle 被作为val$handle 字段复制到内部类。只有当handle 永远不会改变时,这才能正常工作——这在Java 中意味着它必须是final

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

        【讨论】:

          【解决方案4】:

          这个内部类被翻译成类似于以下的代码:

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

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

          【讨论】:

            猜你喜欢
            • 2023-04-01
            • 2015-12-25
            • 1970-01-01
            • 2019-07-29
            • 2015-10-23
            • 2011-01-18
            • 1970-01-01
            • 2013-12-01
            • 2013-06-13
            相关资源
            最近更新 更多