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 implementedFoo
,该lambda implementedFoo
引用了原始的Foo
实例,在第一次求值时将调用compute
,但随后,它将用一个新的lambda implementedFoo
替换自身,该lambda implementedFoo
将始终返回计算值。新的lambda甚至不需要计算条件,因为已经计算了值这一事实是隐含的
请注意,holder对象在这里不必是AtomicReference
,但没有规范的简单易用替代方法。通用数组无法创建,所以我想到的唯一选择是一个大小为1的(可变)列表,例如通过数组创建。asList(null)
你确定这是吗?@Michael我相信是的。你错过了Bar中的foo=null
指令。你会发誓刚才没有它;)是的,你说得对。在这种情况下,将字段设置为null后,Foo
可以被垃圾收集。在这方面,静态内部类的工作方式与外部类完全相同。我的上帝,这真是太巧妙了!我甚至不知道怎么称呼这个,一个“变异”的lambda,一个“自我变异”的lambda?太聪明了