反编译中的 匿名内部类 this.val$的问题

本文探讨了Java反编译过程中遇到的奇怪代码现象,解释了匿名内部类使用外部变量时编译器的处理机制,以及如何正确修改代码以避免反编译带来的误导。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  一天偶尔在网上找到一个jar包,反编译后出现了如下的代码:

public void defineAnonymousInnerClass(String name)
  {
    new Thread(name) {  //extra constructor argument "name"
      public void run() {
        System.out.println(this.val$name); //"this.val$"  is extra
      }
    }
    .start();
  }

  当看到红色的部分时,我就纠结了。这是什么东西还能这么使用?后来在百度上搜索答案,却始终不得答案。最终在google找到了答案。

      链接地址:http://www.mindfiresolutions.com/A-tip-on-val$-field-in-Java-decompiled-code-1725.php

   其实,我是被编译器给玩了。这些代码都是编译器反编译的时候自己添加上去的。

  第一个问题:匿名内部类要使用外面的参数,必须要加final。而代码中却没有加。

  第二个问题:new Thread 这个类没有带参数的构造器。

  第三个问题:this.val$这种用法很怪异,val$是哪里来的。

  这些问题都是反编译器给我们搞的鬼。

  我们在学习匿名内部类的时候都知道,匿名内部类要使用外部的变量,或者参数,这个变量和参数都必须是final类型。而且匿名内部类没有构造器他的构造器是继承于父类,这就还有一个问题就是那我们如何初始化内名内部类中的变量,只需要使用“{}”在里面初始化变量不需要任何修饰。再就是在匿名内部类中this表示当前对象,如果要使用外部类对象需要加上Outclass.this这才是外部对象。

  所以以上代码我们做如下修改:

public void defineAnonymousInnerClass(final String name)//参数加上final
  {
    new Thread() {  //额外的参数去掉
      public void run() {
        System.out.println(name); //"this.val$"  多余的去掉
      }
    }
    .start();
  }

  这时我们就可以正常运行了,其实都是编译器搞的鬼。

  这是我第一次写博客,如有写的不对的地方请各位大侠们指教。

。。。。。

 

一次反编译后出现的问题:

反编译后,导入Eclipse,发现如下错误

问题1:出现 access$002 报错

阅读代码,并没有发现这行代码有什么用处,所以,直接注释掉,经过测试,没有任何问题,可见这行可能是反编译时自动生成的多余代码。

解决方法:

 

直接注释掉。

 

问题2:出现 this.val$jarfilePathText 这样的错误

 

 经过分析代码,发现,这个报错的部分,其实应该就是指前面定义的 变量  JTextField jarfilePathText = new JTextField(10);  因为其非常相似,只是在变量前多了 val$ ,结合前面的博客可知,这是由于反编译时没有给内部类中要使用的变量加final属性。

修改方式:

 

去掉 报错变量的 val$ ,然后在定义的地方 加上 final修饰。

### Java中`Host.getAddress()`方法空指针异常分析 当遇到 `Cannot invoke "com.alibaba.cloud.commons.host.model.Host.getAddress()" because "this.val$host" is null` 错误时,表明程序尝试访问一个未被初始化的对象属性。具体到此案例中,变量 `val$host` 被设为空(null),而后续代码试图调用其成员函数 `getAddress()`。 #### 可能原因及解决方案 1. **检查对象实例化** 需要确认创建 `Host` 实例的地方是否有遗漏或错误逻辑,确保每次使用前都已正确构建并赋予初始值[^1]。 2. **验证数据源可靠性** 如果 `Host` 对象是从外部获取(如数据库查询、API请求),应增加必要的校验机制来处理可能返回null的情况。可以在接收端加入非空判断语句,防止下游操作因上游供给不足而导致崩溃[^3]。 3. **优化编码实践** 使用Optional类可以有效减少显式的null检查,使代码更加简洁安全;同时考虑采用构造器注入的方式代替字段直接赋值,增强不可变性和线程安全性。 4. **调试技巧建议** 利用日志记录功能追踪问题源头,特别是关注那些负责设置 `val$host` 字段的方法执行情况。通过打印堆栈跟踪信息或者借助IDE内置工具逐步排查潜在缺陷所在位置[^2]。 ```java // 示例:引入 Optional 来避免 NPE (Null Pointer Exception) public String getSafeAddress(Host host){ return Optional.ofNullable(host).map(Host::getAddress).orElse("default address"); } ``` 5. **单元测试覆盖** 编写针对涉及 `Host` 和其他依赖组件交互场景下的自动化测试用例,模拟不同输入条件下的行为表现,从而提前发现隐患并及时修正。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值