为什么匿名 类 捕获 "this",即使他们不需要?

Why do anonymous classes capture "this" even if they don't need to?

鉴于此代码:

class Foo {}

public class Test {
        public Foo makeFoo(String p, String q) {
                return new Foo(){
                        public void doSomething() {
                                System.out.println(p);
                        }
                };
        }
}

当你编译它和 运行 javap -c -p 'Test.class' 时,你会得到这个:

Compiled from "Test.java"
class Test extends Foo {
  final java.lang.String val$p;

  final Test this[=13=];

  Test(Test, java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this[=13=]:LTest;
       5: aload_0
       6: aload_2
       7: putfield      #2                  // Field val$p:Ljava/lang/String;
      10: aload_0
      11: invokespecial #3                  // Method Foo."<init>":()V
      14: return

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

创建匿名class时,变量p被捕获到val$p中(符合预期,因为需要),而变量q不是(如预期的那样,因为不需要)。然而,Test.this 被捕获到 this[=19=] 中,即使它不是必需的。这是 Java 规范强制要求的,还是它恰好工作的方式?为什么会这样?

  1. 因为这样做比较简单。例如,字节码编译器中的代码路径更少。

  2. 因为如果他们将需要或不需要这种捕获的情况视为不同的情况(即通过更改有效的构造函数签名),那么这会给需要使用反射创建实例的代码带来巨大的问题, 字节码工程等

另一方面,这可能无关紧要。字节码是 JIT 编译的,JIT 编译器应该能够优化掉未使用的变量(如 this[=10=])。如果值得优化隐藏变量的传递,这也将由 JIT 编译器完成。

请注意:您不能通过查看字节码序列对Java代码效率做出合理的判断。您确实需要查看 JIT 编译器生成的本机代码。


UPDATE - 我在上面写的关于 JIT 编译器功能的内容是推测性的。但是,如果事实证明 JIT 编译器无法优化掉未使用的 this[=10=] 是有根本原因的,那么这很可能也是字节码编译器无法做到这一点的原因。 (我在想当你调试应用程序时会发生什么。)

因为它是一个内部class,并且因为

An instance i of a direct inner class C of a class or interface O is associated with an instance of O, known as the immediately enclosing instance of i. The immediately enclosing instance of an object, if any, is determined when the object is created (§15.9.2).

JLS 8.1.3.

“即使他们不需要”也不例外。