gpt4 book ai didi

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

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:58:19 25 4
gpt4 key购买 nike

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

在 Java 中,为匿名类和 lambda 捕获使用过的局部变量。对于匿名类,无论是否需要,this 也会在非静态上下文中捕获。

然而,即使未用于 Oracle JDK 8 更新 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 的作用大致相同,也捕获变量。

总是这样吗,还是一个实现细节?

最佳答案

规范对“引用”和“使用”变量没有区别。在这方面,您通过调用 t.yield() 使用变量,尽管您正在调用 static 方法。对于这种情况,规范说

JLS §15.12.4.1, 15.12.4.1. Compute Target Reference (If Necessary) :
  • If form is ExpressionName . [TypeArguments] Identifier, then:
    • If the invocation mode is static, then there is no target reference. The ExpressionName is evaluated, but the result is then discarded.
    • Otherwise, the target reference is the value denoted by ExpressionName.

因此行为符合规范。

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

但无论这些指令是否存在,变量 t 都会被使用,因此需要遵守形式要求,即它必须是 effective final

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

换句话说,当您询问值捕获的极端情况时,即被引用但不需要的变量的值,即使是一般情况,即众所周知的内部类始终保持对封闭的 this 的引用,即使不需要,而 lambda 表达式不需要,也不会出现在官方规范中的任何地方。

关于java - 未使用的引用变量总是在 Java 中捕获,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53205627/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com