想象一下这个示例java类:
class A { void addListener(Listener obj); void removeListener(Listener obj); } class B { private A a; B() { a = new A(); a.addListener(new Listener() { void listen() {} } }
我是否需要向B添加finalize方法以调用a.removeListener?假设A实例也将与其他一些对象共享,并且将比B实例更长.
我担心我可能会在这里创建垃圾收集器问题.什么是最佳做法?
参考图中有一个循环.引用B和B引用A.垃圾收集器将检测周期并查看何时没有对A和B的外部引用,然后将收集两者.
试图在这里使用终结器是错误的.如果B被销毁,则对A的引用也将被删除.
声明:"假设A实例也将与其他一些对象共享,并且将比B实例更长." 是错的.唯一的方法是如果从终结器以外的某个地方明确地删除了监听器.如果传递对A的引用,那将意味着对B的引用,并且B将不会被垃圾收集,因为存在对AB循环的外部引用.
进一步更新:
如果要打破循环并且不要求B显式删除侦听器,则可以使用WeakReference.像这样的东西:
class A { void addListener(Listener obj); void removeListener(Listener obj); } class B { private static class InnerListener implements Listener { private WeakReference m_owner; private WeakReference m_source; InnerListener(B owner, A source) { m_owner = new WeakReference(owner); m_source = new WeakReference(source); } void listen() { // Handling reentrancy on this function left as an excercise. B b = (B)m_owner.get(); if (b == null) { if (m_source != null) { A a = (A) m_source.get(); if (a != null) { a.removeListener(this); m_source = null; } } return; } ... } } private A a; B() { a = new A(); a.addListener(new InnerListener(this, a)); } }
如果需要跨多个类可以进一步推广.
我对GC的理解是,在调用removeListener方法之前,类A将维护对侦听器的引用,因此它不会成为GC清理的候选者(因此不会调用finalize).