匿名内部类与局部变量

匿名内部类 与 局部变量

匿名类不能访问外部类方法中的局部变量,除非变量被声明为final类型;

通常在一个方法中, 有局部变量和临时创建的匿名类, 使用时:

Integer i = 8848;
new Thread(
  () -> {
    Integer j = i; // 报错 i 无法使用
    System.out.println("j = " + j);
  })
  .start();
i = 996;

这样除非声明的变量 i 为 final (或者后续不再使用, 编译器会自动转换为 final), 不然无法在内部类中操作局部变量 i .

其实就是内部类的对象在使用它,内部类对象生命周期中都可能调用它, 而内部类试图访问外部方法中的局部变量时,外部方法的局部变量很可能已经不存在了,那么就得延续其生命, 拷贝到内部类中,而拷贝会带来不一致性,从而需要使用 final 声明保证一致性。

此时,内部类会自动拷贝外部变量 的引用,为了避免: 内部类得到的引用值不一致、内部类修改引用,而导致外部方法的参数值在修改前和修改后不一致.

如果是外部类的成员变量就不需要是 final 的,因为内部类本身都会含有一个外部类的引用(外部类.this),所以回调的时候一定可以访问到.

匿名内部类 与 成员变量

  • 成员变量,通过匿名类的构造函数,复制了一份实例的地址引用,去调用实例的属性 (属性为 private 也行),保证了变量改变时数据引用的一致性,不用加 final;
  • 全局变量同理(static),在匿名内部类里,可以直接通过类直接访问变量,可以保证变量引用的一致性,所以不用加 final;

匿名内部类定义

  • 匿名内部类: 在类的成员方法内,同时完成定义实例化的类。拥有语法糖,编译器帮忙创建类,这个匿名在编译后其实已经有名字了,通过这个编译生成的类名,去创建对象,跟正常的实现类的流程是一样的。
              ch.pipeline()
                      .addLast(
                              new ChannelDuplexHandler() {
                                  // 处理 读写之外的 特殊的事件
                                  @Override
                                  public void userEventTriggered(
                                          ChannelHandlerContext ctx, Object evt) throws Exception {
                                      IdleStateEvent event = (IdleStateEvent) evt;
                                      // 是否 读超时
                                      if (event.state() == IdleState.WRITER_IDLE) {
                                          ctx.writeAndFlush(new PingMessage());
                                      }
                                  }
                              });
  						// 又或者这样的
              return ()-> {};
  • 原因: 编译程序实现上的困难, 内部类对象的生命周期会超过局部变量的生命周期。

    • 局部变量的生命周期:当该方法被调用时,该方法中的局部变量在栈中被创建,当方法调用结束时,退栈,这些局部变量全部死亡。
    • 而内部类对象生命周期与其它类一样:自创建一个匿名内部类对象,系统为该对象分配内存,直到没有引用变量指向分配给该对象的内存,它才会死亡(被JVM垃圾回收)。
  • 所以完全可能出现的一种情况是:成员方法已调用结束,局部变量已死亡,但匿名内部类的对象仍然活着。如果匿名内部类的对象访问了同一个方法中的局部变量,就要求只要匿名内部类对象还活着,那么栈中的那些它要所访问的局部变量就不能“死亡”。

过程

匿名内部类对象访问同一个方法中被定义为final类型的局部变量。定义为 final 后,编译程序的实现方法:对于匿名内部类对象要访问的所有final类型局部变量,都拷贝成为该对象中的一个数据成员。这样,即使栈中局部变量已死亡,但被定义为final类型的局部变量的值永远不变,因而匿名内部类对象在局部变量死亡后,照样可以访问final类型的局部变量,因为它自己拷贝了一份,且与原局部变量的值始终一致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值