匿名类和父类之间的循环依赖关系是错误的吗?

我有以下代码片段:

public class Example {

private Integer threshold;

private Map<String, Progress> history;

protected void activate(ComponentContext ctx) {
    this.history = Collections.synchronizedMap(new LinkedHashMap<String, Progress>() {
        @Override
        protected boolean removeEldestEntry(Map.Entry<String, Progress> entry) {
            return size() > threshold;
        }
    });
  }
}

匿名类和类之间存在循环依赖关系。这是可以的还是不行的?为什么不呢?垃圾回收器会很好地回收它吗?LinkedHashMapExample


答案 1

这是可以的还是不行的?

这完全没问题。

threshold是一个字段,因此可以从匿名类中引用它,而不会出现任何问题。(如果它是一个局部变量,它必须(有效地)是最终的。threshold

类之间的循环依赖关系很常见,当依赖关系图很小时(如本例中),它不会造成任何问题。事实上,你是一个匿名类在这里并不重要。LinkedHashMap

垃圾回收器会很好地回收它吗?

关于内存泄漏 + 内部类,唯一需要注意的是,(非静态)内部类对其封闭对象具有隐式引用。这意味着,如果创建大量内部类的实例,则不能期望外部类对象的实例被垃圾回收。

在这种情况下,这意味着如果您泄漏对地图的引用,则不会对 的实例进行 GC'ed。historyExample


相关说明:

  • 考虑到你正在使用它,你似乎正在研究一个多线程程序。如果是这种情况,您需要警惕字段的同步和可见性问题。synchronizedMapthreshold

  • 如果可能,请尝试使该字段最终确定threshold

  • 另一种选择是为您的类创建一个命名类,并作为字段包含在该类中。LinkedHashMapthreshold


答案 2

无论如何,您都有此依赖关系,因为匿名内部类的每个对象都对封闭类的对象进行了隐式引用。Java就是这样设计的,嵌套的内部类有这个引用是有原因的,所以从语言规范的角度来看,这编译并且看起来完全正常。

关于(缺少)“设计气味”,如果这个匿名类对象完全封装在类中,没有其封闭上下文就没有显著的含义,并且没有泄漏到类以外的任何地方,那么引用封闭类的字段就没有错。您只需使用此内部类对某些逻辑进行分组即可。ExampleExample

但是,如果此对象从封闭对象中泄漏出来(例如,通过 getter 返回它),则应禁止此操作,或者将其重构为作为参数接收的静态内部类。此内部对象保存对封闭对象的引用,并可能将其保留在 GC 中,从而导致内存泄漏。threshold


推荐