如果非最终字段的值可以更改,如何在匿名类中使用它们?

2023-12-30

我之前问过这个问题,但没有得到合适的答案。

如果非最终字段的值可以更改,如何在匿名类中使用它们?

class Foo{
    private int i;
    void bar(){
        i = 10
        Runnable runnable = new Runnable (){
            public void run (){
                System.out.println(i); //works fine
            }//end method run
        }//end Runnable
    }//end method bar
}//end class Foo 

如果在匿名类中使用的局部变量必须是final使编译器能够将它们的值内联到匿名类代码中,如下所示:

Before:

public class Access1 {
  public void f() {
    final int i = 3;
    Runnable runnable = new Runnable() {
        public void run() {
            System.out.println(i);
        }//end method run
    };//end anonymous class
  }//end method f
}//end class Access1

After:

public class Access1 {
    public Access1() {}//end constructor

    public void f() {
        Access1$1 access1$1 = new Access1$1(this);
    }//end method f
}//end class Access1

And

class Access1$1 implements Runnable {
    Access1$1(Access1 access1) {
        this$0 = access1;
    }//end constructor

    public void run() {
        System.out.println(3);
    }//end method run
    private final Access1 this$0;
}//end class Access1$1

Then 编译器如何内联非最终字段的值?


方法调用的局部变量(必须是final可供内部类访问)以及实例的私有数据成员。

内部类可以访问包含实例以及该实例的所有成员,final或不。它们不需要是最终的,因为它们是通过(在您的情况下)引用的Foo.this。所以当访问你的imember,内部类确实在访问Foo.this.i,仅此而已Foo.this (like this) 可以被暗示,如果没有它的引用是明确的。

但是匿名类的代码无法以这种方式访问​​局部变量,因为它们(当然)不是包含类的实例成员。因此,编译器做了一件非常有趣的事情:它创建了一个实例成员匿名的每个班级final局部变量,并且在创建匿名类的实例时,它使用局部变量的值初始化这些成员。

让我们看一下它是如何做到的:

public class InnerEx {
    public static final void main(String[] args) {
        new InnerEx().test("hi");
    }

    private void test(String arg) {
        final String localVar = arg;

        Runnable r = new Runnable() {
            public void run() {
                System.out.println(localVar);
            }
        };
        r.run();
    }
}

编译后,我们得到InnerEx.class and InnerEx$1.class。如果我们反编译InnerEx$1.class,我们看到这个:

class InnerEx$1 implements java.lang.Runnable {
  final java.lang.String val$localVar;

  final InnerEx this$0;

  InnerEx$1(InnerEx, java.lang.String);
    Code:
       0: aload_0       
       1: aload_1       
       2: putfield      #1                  // Field this$0:LInnerEx;
       5: aload_0       
       6: aload_2       
       7: putfield      #2                  // Field val$localVar:Ljava/lang/String;
      10: aload_0       
      11: invokespecial #3                  // Method java/lang/Object."<init>":()V
      14: return        

  public void run();
    Code:
       0: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: aload_0       
       4: getfield      #2                  // Field val$localVar:Ljava/lang/String;
       7: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      10: return        
}

请注意名为的实例成员val$localVar,这是为代表调用中的局部变量而创建的实例成员InnerEx#test.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果非最终字段的值可以更改,如何在匿名类中使用它们? 的相关文章

随机推荐

  • 如何在 Windows 8.1 Phone 的子目录中包含“内容”文件?

    我正在开发一个包含大量文件的项目 游戏 这些文件可以从 VS 2013 外部更改 例如由艺术家 这些文件位于子目录中 我们的游戏需要它们在那里 例如 images items block png 我尝试过使用构建后事件 xcopy C Y
  • 创建 JObject C# 时删除双花括号

    我正在尝试使用下面提到的结构创建 JsonObject id 1 name XXX age 30 使用代码 dynamic sampleJson new JObject sampleJson Add id 1 sampleJson Add
  • 让我的 jQuery Ajax 脚本使用 CORS

    我构建了一个通过 AJAX 从外部网站读取数据的应用程序 它工作正常 但我在另一个中发现question https stackoverflow com a 10881561 773263如果我想使用 Webworks 或 Phonegap
  • 如何使用 shelf_web_socket 监听同一端口上的 http 和 ws 请求

    https pub dartlang org packages shelf web socket https pub dartlang org packages shelf web socket显示这个例子 import package s
  • 即使为空,复选框也会绑定(数据表控件)

    我需要将我的复选框绑定到某处 即使它为空 这样我就不会收到有关无效转换的错误 DataTable dt new DataTable dt Columns Add Name dt Columns Add DeleteFlag typeof b
  • 如何避免“IndexError:列表索引超出范围”错误?

    假设有一个名为 my list 和一个名为 的 int 变量list index 基本上 列表 my list 可能会随着时间而改变 因此 list index 可能会提高 IndexError list index out of rang
  • 如何使用 Dart 将剪贴板中的图像粘贴到 Canvas 元素上?

    我正在使用 Dart 开发个人白板 Chrome 应用程序 有时能够快速复制和粘贴图像 例如演示文稿中的幻灯片 图表或讲义 很有用 以便我可以在图像上添加注释在授课或进行演示时 如何将剪贴板上存储的图像粘贴到 Dart 中的画布元素上 实际
  • 无法启动浏览器进程!/usr/bin/chromium-browser'需要安装 chromium snap

    我正在尝试使用 puppeteer 的 api 它基本上有一个功能可以吸引我不和谐的用户 不太熟悉 puppeteer 所以介意我缺乏解释 做了一些研究并找到了一些解决方案 例如手动安装 chromium 这样做了 运行 puppeteer
  • 编译 gSOAP 客户端时未定义的引用

    我正在尝试使用 C 语言为 Web 服务创建客户端 我使用 wsdl2h 和soapcpp2 生成了 C 文件 在 netbeans 中 我将生成的文件和 gSOAP 包含目录添加到项目的包含目录中 我的主文件如下所示 include
  • 将 VSTO 部署到一个安装程序中

    我已经使用 ClickOnce 部署了 VSTO 应用程序 并得到了以下结果 这个安装程序工作得很好 然而 我真正想要的是一个安装程序 例如单个 exe 文件或单个 msi 文件 这样分发起来会很方便 我想我必须将所有 dll xml vs
  • 如何仅选择数值

    Table1 id 01 wire 02 steve ram123 03 从表1中我只想选择数值 它不应显示字母数字值 如 ram123 预期输出 01 02 03 如何查询这个条件 Try ISNUMERIC http msdn micr
  • C# 中 C++ const size_t 的等效项是什么?

    我正在尝试将一些 Ogre 代码转换为 C 版本 但遇到了一个问题 const size t nVertices 8 const size t vbufCount 3 2 nVertices float vertices vbufCount
  • 在Python中检查较长字符串中存在的模糊/近似子字符串?

    使用像leveinstein leveinstein或difflib 这样的算法 很容易找到近似匹配 gt gt gt import difflib gt gt gt difflib SequenceMatcher None amazing
  • 无法将 void* 动态转换为模板类

    我得到的确切错误是 无法将 object 类型为 void 动态转换为类型 class udDator int 源不是指向类的指针 这是在重写的运算符删除内部发生的 我正在尝试创建一个模板化内存管理类 它可以继承到任何其他类 通过引用管理内
  • Graphviz / PyGraphviz 中有向图的 NetworkX 风格弹簧模型布局

    NetworkX 主要用于图形分析 PyGraphviz 主要用于绘图 它们被设计为协同工作 然而 至少在一个方面 NetworkX 的图形绘制 通过 MatPlotLib 优于 PyGraphviz 的图形绘制 通过 Graphviz 即
  • Oracle 列别名中的双引号

    好吧 这是一个有点晦涩的问题 但希望有人能帮助我解决这个问题 我正在开发的系统构建了一个用于在存储过程中执行的动态 SQL 字符串 以及定义列别名的动态 SQL 的一部分 这些别名本身实际上是从用户生成的数据的另一个表中检索的值 因此 例如
  • 无限循环动画

    我正在尝试创建无限循环的动画 但遇到了一些麻烦 我正在使用这行代码 使我的视图 颤动 为红色 但是当我调用这一行时 它可以工作 但使我的用户界面无响应 UIView animateWithDuration 1 0f delay 0 0f o
  • 如何更改 Braintree 上的订阅期限?

    我想为我们使用 Braintree 的计费系统添加一些单元测试 但我不知道如何将订阅期从 1 个月 目前 Braintree 中的最小值 更改为 1 天 我等不及 1 个月来执行我的测试 有什么解决办法吗 我最近向 Braintree 支持
  • 如何检查哈希中是否存在特定密钥?

    我想检查会话哈希中是否存在 用户 密钥 我怎样才能做到这一点 请注意 我不想检查键的值是否为零 我只是想检查 用户 是否key存在 Hash s key 方法告诉您给定的密钥是否存在 session key user
  • 如果非最终字段的值可以更改,如何在匿名类中使用它们?

    我之前问过这个问题 但没有得到合适的答案 如果非最终字段的值可以更改 如何在匿名类中使用它们 class Foo private int i void bar i 10 Runnable runnable new Runnable publ