当方法中有最终值和内部类时,究竟会发生啥?

Posted

技术标签:

【中文标题】当方法中有最终值和内部类时,究竟会发生啥?【英文标题】: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();

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

【问题讨论】:

【参考方案1】:

以下是对其工作原理的详细说明:http://techtracer.com/2008/04/14/mystery-of-accessibility-in-local-inner-classes/

【讨论】:

【参考方案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();

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

【讨论】:

以上是关于当方法中有最终值和内部类时,究竟会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

当我们重新启动 Azure Databricks 群集时,内部会发生啥?

当Java类注释@WebService时会发生什么?

测试类时,使用 Junit 和 Mockito 检查方法内部的工作

当我们按键加入两个 Stream 组时,内部会发生啥?

当您在 php 中调用函数时,内部会发生啥

装饰器和继承:当装饰器应用于父类时会发生啥