Java-匿名内部类生命周期

Java-匿名内部类生命周期,java,Java,当使用匿名内部类作为PropertyChangeListener时,该类在对象生命周期的什么时候被垃圾收集?回收包含类(SettingsNode)后?我是否应该在包含类(SettingsNode)的终结器中显式删除PropertyChangeListener 与所有对象一样,当对匿名内部类的最后一个引用不再引用它时,它也有资格被垃圾收集。我在这里使用的是黄鼠狼(weasel)的措辞,因为Java不能保证事情会被GC’d——唯一的保证是,只要有引用,它就不会发生 在这种特殊情况下,当project

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


与所有对象一样,当对匿名内部类的最后一个引用不再引用它时,它也有资格被垃圾收集。我在这里使用的是黄鼠狼(weasel)的措辞,因为Java不能保证事情会被GC’d——唯一的保证是,只要有引用,它就不会发生

在这种特殊情况下,当
projectSettings
执行
removePropertyListener()
或其本身被垃圾收集时


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

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

在您显示的示例中,在回收项目设置之前,无法回收设置节点和侦听器

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

在删除PropertyChangeListener之前,设置节点不会被回收。为侦听器使用匿名类可能是内存泄漏的常见原因

编辑Alex B的以下问题:

如果在应用程序的生命周期内存在projectSettings,则无法删除匿名侦听器,因为注册后您没有对它的引用。
当创建多个SettingsNode实例时,它们将在构造函数中添加它们的侦听器,但它们永远不会被删除,因为没有其他人引用它们。这将阻止删除设置节点,并且侦听器会引用设置节点,这是内存泄漏的典型情况。不建议finalize,因为它可能会延迟GC。您可以公开清理函数或重写dispose并取消注册


真的很奇怪为什么swing没有内置弱侦听器注册。也许你可以在SourceForge中尝试一些开源软件?

这个问题已经过时了

然而,我不同意这里的大多数答案

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

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

虽然PropertyChangeListener对象确实引用了其包含对象设置节点,但这并不阻止包含对象被取消引用和垃圾收集


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

@Aaron:你能举一个内存泄漏的例子吗?@Alex:问题中的代码实际上已经是内存泄漏的例子,如果它在不再需要设置节点时不删除侦听器。Carl的回答解释了这种情况。虽然Java不能保证什么时候会被GC'd,但我想你必须说,如果另一种选择是OutOfMemoryError,它保证什么时候会被GC'd。现在你已经说了,我不必再做了:)你当然是对的,谢谢你;但是我希望我们的读者都不会编写依赖于这种行为的代码。根据提供的答案,匿名似乎不是这个用例的最佳选择。我现在认为实例内部类可能是一个更好的选择,因为我可以持有一个引用并在将来某个时候调用removePropertyListener方法。
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
                }
            });
     }
}