Java - 匿名内部生命周期

时间:2010-01-20 20:05:42

标签: java

当使用匿名内部类作为PropertyChangeListener时,对象生命周期中的哪一点是收集的类垃圾?收回包含类(SettingsNode)后?我应该在包含类(SettingsNode)的终结器中显式删除PropertyChangeListener吗?

public class SettingsNode extends AbstractNode
{
    public SettingsNode(Project project, ProjectSettings projectSettings)
        throws IntrospectionException
    {   
        // use an anonymous inner class to listen for changes
        projectSettings.addPropertyChangeListener(ProjectSettings.PROP_NAME,
            new PropertyChangeListener()
            {
                @Override
                public void propertyChange(PropertyChangeEvent evt)
                {
                   // handle event
                }
            });
     }
}

5 个答案:

答案 0 :(得分:7)

与所有对象一样,匿名内部类可以在最后一次引用它时不再引用它时收集垃圾。我在这里使用weasel措辞,因为Java并不能保证事情会被GC化 - 唯一的保证就是只要有参考就不会发生。

在这种特殊情况下,那就是当projectSettings执行removePropertyListener()或者本身是垃圾收集时。

因为projectSettings引用了匿名内部类,并且因为内部类引用了它的包含类,这意味着包含类也将至少与内部类一样长。

答案 1 :(得分:2)

您正在将要创建的PropertyChangeListener类添加到projectSettings对象。只要projectSettings引用它,就不会收集PropertyChangeListener。

答案 2 :(得分:2)

在示例中,您已显示设置节点,并且在回收项目设置之前无法回收侦听器。

您需要显式删除侦听器,但您应该寻找比终结器更可靠的地方。

在删除PropertyChangeListener之后,才会收回SettingsNode。对侦听器使用匿名类会导致内存泄漏的常见原因。

编辑Alex B的问题:

如果projectSettings在应用程序的生命周期中存在,则无法删除匿名侦听器,因为在注册后没有对它的引用。 在创建多个SettingsNode实例时,它们将在构造函数中添加它们的侦听器,但它们永远不会被删除,因为没有其他人具有对它们的引用。这将阻止SettingsNodes被删除,并且侦听器也会引用SettingsNodes

答案 3 :(得分:1)

这个问题很陈旧。

但是,我不同意这里的大部分答案。

无需显式删除侦听器。在这种情况下,内部类PropertyChangeListener对象将一直存在,直到收集包含的实例SettingsNode为止。

您实际上无法删除PropertyChangeListener对象,因为没有为它保留引用。

虽然PropertyChangeListener对象引用其包含的对象SettingsNode,但这并不会阻止包含对象被取消引用和垃圾回收。

一旦取消引用包含对象,SettingsNode包含的所有对象就变成“隔离岛”。所有这些都将被垃圾收集。

答案 4 :(得分:0)

内存泄漏的典型场景。不建议最终确定,因为它可能会延迟GC.You可以暴露清理功能或覆盖处置和取消注册。

真的很惊讶为什么swing没有内置弱听众注册。可能你可以在source forge中尝试一些开源?