Java 解决封闭实例不符合垃圾收集条件的问题

Java 解决封闭实例不符合垃圾收集条件的问题,java,garbage-collection,inner-classes,anonymous-inner-class,Java,Garbage Collection,Inner Classes,Anonymous Inner Class,只要封闭实例处于活动状态,这里的封闭实例就不符合垃圾收集的条件,对吗 interface Foo<T> { T compute(); default Foo<T> memoize() { return new Foo<>() { T result = null; boolean cached = false; @Override

只要封闭实例处于活动状态,这里的封闭实例就不符合垃圾收集的条件,对吗

interface Foo<T> {
    T compute();

    default Foo<T> memoize() {
        return new Foo<>() {
            T result = null;

            boolean cached = false;

            @Override
            public T compute() {
                if (!cached) {
                    result = Foo.this.compute();
                    cached = true;
                }
                return result;
            }
        };
    }
}
接口Foo{
T计算();
默认的Foo memoize(){
返回新的Foo(){
T结果=null;
布尔值=假;
@凌驾
公共计算机{
如果(!缓存){
result=Foo.this.compute();
缓存=真;
}
返回结果;
}
};
}
}
这能解决这个问题吗

interface Foo<T> {
    T compute();

    default Foo<T> memoize() {
        return Foo.memoize(this);
    }

    private static <T> Foo<T> memoize(Foo<T> original) {
        class Bar implements Foo<T> {
            T result = null;

            Foo<T> foo;

            Bar(Foo<T> original) {
                foo = original;
            }

            @Override
            public T compute() {
                if (foo != null) {
                    result = foo.compute();
                    foo = null;
                }
                return result;
            }
        }
        return new Bar(original);
    }
}
接口Foo{
T计算();
默认的Foo memoize(){
返回Foo.memoize(本);
}
私有静态Foo memoize(Foo原始){
类栏实现了Foo{
T结果=null;
富富,;
酒吧(原版){
foo=原件;
}
@凌驾
公共计算机{
如果(foo!=null){
结果=foo.compute();
foo=null;
}
返回结果;
}
}
返回新条(原件);
}
}
不,为什么会这样

memoize()
函数中的
Bar
实例有一个保存
Foo
对象的字段。无论您是通过作用域还是通过隐式字段分配来持有它,都与垃圾收集无关


如果要保留对可以垃圾收集的对象的引用,请使用
WeakReference
/
SoftReference

在第一种情况下,匿名内部类通过使用
Foo来“捕获”对封闭的
Foo
的引用。由于匿名类无限期地保留此引用,因此在匿名类也符合条件之前,封闭的
Foo
不符合垃圾收集的条件

在第二个示例中,在
compute
被调用一次后,该引用被丢弃,因此在此之后,封闭类有资格进行垃圾收集


请参见

注意,可以选择使用lambda表达式,因为lambda表达式只捕获需要的值,例如

interface Foo<T> {
    T compute();

    default Foo<T> memoize() {
        AtomicReference<Foo<T>> holder = new AtomicReference<>();
        holder.set(() -> {
               T result = compute();
               holder.set(() -> result);
               return result;
            }
        );
        return () -> holder.get().compute();
    }
}
接口Foo{
T计算();
默认的Foo memoize(){
AtomicReference holder=新的AtomicReference();
固定器组(()->{
T结果=计算();
保持器设置(()->结果);
返回结果;
}
);
return()->holder.get().compute();
}
}
holder
最初包含一个lambda implemented
Foo
,该lambda implemented
Foo
引用了原始的
Foo
实例,在第一次求值时将调用
compute
,但随后,它将用一个新的lambda implemented
Foo
替换自身,该lambda implemented
Foo
将始终返回计算值。新的lambda甚至不需要计算条件,因为已经计算了值这一事实是隐含的


请注意,holder对象在这里不必是
AtomicReference
,但没有规范的简单易用替代方法。通用数组无法创建,所以我想到的唯一选择是一个大小为1的(可变)列表,例如通过
数组创建。asList(null)

你确定这是吗?@Michael我相信是的。你错过了Bar中的
foo=null
指令。你会发誓刚才没有它;)是的,你说得对。在这种情况下,将字段设置为null后,
Foo
可以被垃圾收集。在这方面,静态内部类的工作方式与外部类完全相同。我的上帝,这真是太巧妙了!我甚至不知道怎么称呼这个,一个“变异”的lambda,一个“自我变异”的lambda?太聪明了