方法局部内部 类 中的合成字段如何链接到方法局部变量的值?

How does Synthetic Fields within the Method Local Inner Classes are being linked to the values of the Method Local Variables?

在Java中,只要方法正在执行,方法局部变量就存在于堆栈中,因此对于Method Local Inner 类访问方法局部变量,编译器创建的副本将这些变量放入堆中,这就是为什么这些变量应该是最终的或实际上是最终的:以便存储在堆中的副本保存实际有效值。

所以我知道 Javac 在本地内部 classes 中创建合成字段(源代码中不存在但由编译器创建的字段),并且问题是这实际上是如何工作的,它是否像在局部内部 class 中创建一个字段,其与方法局部变量相同,该变量与该变量具有相同的值,以便内部 class 访问新的创建了一个还是其他东西,除了方法局部内部 classes 的合成字段之外,一般来说合成元素究竟意味着什么? (我已经阅读 JLS,现在希望找到更清楚的东西?)

代表本地 class 的 class 文件中的合成字段有一个损坏的名称。

javap -c -s 可以用来找出 javac 做了什么。

举下面这个简单的例子class。

class Code {
    public static void main(String[] args) throws Throwable {
        class MyLocal {
            void fn() {
                System.err.println(args.length);
            }
        }
        new MyLocal().fn();
    }
}

编译后,javap -c -s Code$1MyLocal.class 给出:

class CodeMyLocal {
  final java.lang.String[] val$args;
    descriptor: [Ljava/lang/String;

  CodeMyLocal();
    descriptor: ([Ljava/lang/String;)V
    Code:
       0: aload_0
       ...

args 的合成字段称为 val$args。我添加了 -s 选项,所以我们看到 MyLocal 的无参数构造函数在编译时实际上有一个参数。 javap -c Code.class 显示调用该构造函数的字节码:

   0: new           #7                  // class CodeMyLocal
   3: dup
   4: aload_0
   5: invokespecial #9                  // Method CodeMyLocal."<init>":([Ljava/lang/String;)V

编译器的工作方式与您自己编译时的工作方式略有不同。如果我们进一步查看本地 class 构造函数的反汇编,我们会发现它在调用 superclass 构造函数之前分配了一个字段。

  CodeMyLocal();
    descriptor: ([Ljava/lang/String;)V
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field val$args:[Ljava/lang/String;
       5: aload_0
       6: invokespecial #7                  // Method java/lang/Object."<init>":()V
       9: return

这相当于:

    class MyLocal extends Object {
        private final String[] args;
        MyLocal(String[] args) {
            this.args = args;
            super();
        }
        ...
    }

不会在 Java 中编译。在 Java 1.4 之前,这没有发生。您最终可能会观察到合成字段的默认值,通常会导致 NullPointerException.