gpt4 book ai didi

java - 匿名类*总是*维护对其封闭实例的引用吗?

转载 作者:行者123 更新时间:2023-12-01 04:37:54 27 4
gpt4 key购买 nike

我正在处理一些代码,其中一个对象“foo”正在创建另一个对象对象“bar”,并向其传递一个Callable。之后 foo 将返回bar,然后我希望 foo 变得无法访问(即:可用于垃圾收集)。

我最初的想法是匿名创建Callable。例如:

class Foo {
...

public Bar createBar() {
final int arg1 = ...
final int arg2 = ...
final int arg3 = ...
return new Callable<Baz>() {
@Override
public Baz call() {
return new Baz(arg1, arg2, arg3);
}
};
}
}

我突然想到,这实际上可能无法按预期工作,但是,作为内部类通常保留对其封闭对象的引用。我不想在这里引用封闭类,因为我希望封闭对象是当 Callable 仍然可达时收​​集。

另一方面,检测到封闭实例从未被实际引用应该是相当微不足道的,所以也许 Java 编译器足够聪明在这种情况下不包含引用。

那么...匿名内部类的实例是否会持有对其封闭实例的引用,即使它从未实际使用过包含实例引用吗?

最佳答案

从 JDK 18 开始,没有。 JDK 18 omits enclosing instance fields from inner classes that don't use it.

但是,在 JDK 18 之前,匿名内部类的实例会保留对其封闭实例的引用,即使这些引用从未实际使用过。例如,这段代码:

public class Outer {
public Runnable getRunnable() {
return new Runnable() {
public void run() {
System.out.println("hello");
}
};
}
}

...使用 javac 编译时,生成两个类文件:Outer.class外部$1.class。拆解后者,匿名内部类,使用 javap -c 会产生:

Compiled from "Outer.java"
class Outer$1 extends java.lang.Object implements java.lang.Runnable{
final Outer this$0;

Outer$1(Outer);
Code:
0: aload_0
1: aload_1
2: putfield #1; //Field this$0:LOuter;
5: aload_0
6: invokespecial #2; //Method java/lang/Object."<init>":()V
9: return

public void run();
Code:
0: getstatic #3; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #4; //String hello
5: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return

}

putfield 行显示对封闭实例的引用是由构造函数存储在 this$0 字段(类型为 Outer)中即使这个字段再也没有被使用过。

如果你试图创造小的潜在机会,这是不幸的具有匿名内部类的长生命周期对象,因为它们将保留(可能很大)封闭实例。解决方法是使用静态类(或顶级类)的实例。不幸的是,这更加冗长。

关于java - 匿名类*总是*维护对其封闭实例的引用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17063982/

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