JPanel with anonymous EventListeneR语言 为什么 GC 不销毁侦听器?



我一直在阅读JMapViewer的开源代码。如果有人想看它,请检查SVN。

简而言之,主类是JMapViewer,它是JPanel的扩展。还有一个非常重要的类叫做DefaultMapController,它充当了主类的MouseListener

我注意到的第一个奇怪的事情是查看器没有指向控制器的引用。JMapViewer构造函数实例化了DefaultMapController的匿名实例,如下所示:

public JMapViewer() {
    // other stuff
    new DefaultMapController(this);
}

在我看来,这似乎是一个糟糕的设计选择,因为控制器有大量的方法(选项,切换等-如下所示的例子),现在根本无法访问,所以他们有什么好处?

public void setMovementMouseButton(int movementMouseButton) {
    // changes which mouse button is used to move the map
}

控制器确实有一个对查看器的引用,如上面的第一个代码片段所示,这就是它如何能够行使控制。

然而,然后我想到了更奇怪的事情!如果侦听器的这个匿名实例没有引用,为什么允许它存活呢?GC不应该尽快销毁它吗?或者GC是否足够聪明,知道引用活动JComponent的侦听器类也必须保持活动才能正常工作,即使它由于某些奇怪的原因没有名称?

那么,两个真正的问题:

  • 为什么GC不销毁对象?
  • 这确实是一个糟糕的设计选择,还是有一些方式我不知道从实例化查看器的类访问控制器?

我想为这个开源库做出贡献,我的第一个想法是改变JMapViewer类,使其有一个引用其控制器的字段,并改变构造函数,将当前匿名控制器分配给这个新字段。但是,我想确保我没有无知地错过什么。我已经搜索了文本DefaultMapController的整个代码库,它只发生在它自己的类定义中,以及JMapViewer构造函数中的匿名实例化中。


编辑:

似乎确实有一种方法可以访问匿名侦听器,通过使用java.awt.Component方法getMouseListeners()。因此,从技术上讲,在我的应用程序中,我可以搜索这个集合中的DefaultMapController实例,并使用它来访问我需要使用的方法来更改控制器选项。

说句反话,如果我遵循最初的想法,给地图一个控制器的参考,现在我就有了一种循环参考(地图知道控制器,控制器也知道地图)。这是个坏主意吗?

抽象父类JMapController持有DefaultMapController构造函数传递给JMapViewer的引用:

public DefaultMapController(JMapViewer map) {
    super(map);
}

附录:控制器持有的map引用用于(选择性地)将最多三个控制器引用加到映射的EventListenerList,这里讨论。其中任何一个都可以排除GC。至少一个有益的设计好处是,一个具体的JMapController只需要实现可用的接口。

正如这个MVC大纲所建议的那样,给视图一个对控制器的引用是不寻常的。相反,让控制器注册为视图的监听器并没有错,就像这里建议的那样。

注意,只有无参数的JMapViewer构造函数安装DefaultMapController。您可以使用备用构造函数,如Demo.java的29113版第57-59行注释中所述。这里有一个完整的示例。

1)您所知道的是,如果并且当VM认为合适时,它将收集部分或全部死对象。GC不需要做任何事情。

2)最好的方法是向库的维护者询问。无论如何,作为一般规则,我不会费心去改变任何东西,除非有一个很好的理由,例如,如果它明显提高了可读性,我宁愿把自己集中在真正的问题上。

3)不确定情况是否如此,但是,当您序列化一个JComponent时,您也序列化了它的所有字段。而且您也不想序列化大量未使用的内容。

相关内容

  • 没有找到相关文章

最新更新