代码之家  ›  专栏  ›  技术社区  ›  Peter Lawrey

Java中总是捕获未使用的引用变量

  •  10
  • Peter Lawrey  · 技术社区  · 7 年前

    我想知道这是否是一个实现细节。。。

    this 也可以在非静态上下文中捕获,无论是否需要。

    然而,即使没有用于oraclejdk8更新181,也会捕获引用的任何局部变量。

    public static void main(String[] args) {
        Thread t = Thread.currentThread();
        Runnable run = new Runnable() {
            @Override
            public void run() {
                t.yield();
            }
        };
        Runnable run2 = () -> t.yield();
        run.run();
        run2.run();
    }
    

    匿名用户的字节码 Runnable 是

      // access flags 0x1
      public run()V
       L0
        LINENUMBER 8 L0
        ALOAD 0
        GETFIELD UnusedLocalVariable$1.val$t : Ljava/lang/Thread;
        POP
        INVOKESTATIC java/lang/Thread.yield ()V
       L1
        LINENUMBER 9 L1
        RETURN
       L2
        LOCALVARIABLE this LUnusedLocalVariable$1; L0 L2 0
        MAXSTACK = 1
        MAXLOCALS = 1
    

    如您所见,它捕获它加载的局部变量,但总是在运行时丢弃。

    lambda也做了同样的事情,也捕获了变量。

    1 回复  |  直到 7 年前
        1
  •  7
  •   Community Mohan Dere    6 年前

    该规范对引用和使用变量没有区别。在这方面,你 是 通过调用 t.yield() static 方法。对于这种情况,规范说

    JLS §15.12.4.1, 15.12.4.1. Compute Target Reference (If Necessary)
    • 如果窗体是 表达式名称[类型参数]标识符 ,然后:
      • ,则没有目标引用。这个 表达式名称
      • 否则,目标引用是由 .

    虽然很明显,评估必须发生,但当它有副作用时,我不会得出这样的结论:字节码序列 ALOAD 0 , GETFIELD , POP 严格要求满足形式规则,即对变量求值并丢弃结果,因为该代码根本没有任何效果。

    但不管这些指令是否存在,变量 t .

    此强制行为是否必须导致在内部类resp的实例中捕获值。为lambda表达式生成的类,可能令人惊讶的是,完全没有指定。Java语言规范对此没有任何说明。

    换言之,当您询问值捕获的一个角落情况时,即被引用但不需要的变量的值,甚至是一般情况,即众所周知的规则,即内部类始终保留对封闭类的引用 this