Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 小程序 Arthas JVM AQS juc Kubernetes Docker DevOps


为什么匿名内部类引用外部局部变量必须要加 final 关键字

Java 面试 大约 1574 字

Java 代码

public class Test {

    public static void main(String[] args) {
        final int x = 10;
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println(x);
            }
        };
    }

}

匿名内部类

匿名内部类Test$1.class反编译后的代码。

可以看到:匿名内部类引用外部局部变量是其实是通过生成了一个Test$1类,构造函数中传递了外部的变量,所以不能更改。

class Test$1 implements Runnable {
    final int val$x;
    Test$1(final int val$x) {
        this.val$x = var1;
    }

    public void run() {
        System.out.println(this.val$x);
    }
}

字节码

// class version 52.0 (52)
// access flags 0x20
class com/example/Test$1 implements java/lang/Runnable {

  // compiled from: Test.java
  OUTERCLASS com/example/Test main ([Ljava/lang/String;)V
  // access flags 0x0
  INNERCLASS com/example/Test$1 null null

  // access flags 0x1010
  final synthetic I val$x

  // access flags 0x0
  <init>(I)V
    // parameter final synthetic  val$x
   L0
    LINENUMBER 7 L0
    ALOAD 0
    ILOAD 1
    PUTFIELD com/example/Test$1.val$x : I
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/example/Test$1; L0 L1 0
    MAXSTACK = 2
    MAXLOCALS = 2

  // access flags 0x1
  public run()V
   L0
    LINENUMBER 10 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 0
    GETFIELD com/example/Test$1.val$x : I
    INVOKEVIRTUAL java/io/PrintStream.println (I)V
   L1
    LINENUMBER 11 L1
    RETURN
   L2
    LOCALVARIABLE this Lcom/example/Test$1; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1
}
阅读 354 · 发布于 2022-05-17

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批