带有匿名EventListener的JPanel - 为什么GC不会破坏监听器?

时间:2012-12-24 01:58:13

标签: java swing garbage-collection event-listener jmapviewer

我一直在浏览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的实例,并使用它来访问我需要用来更改控制器选项的方法。

虽然玩魔鬼的拥护者,如果我按照原始想法并给地图一个参考其控制器,现在我有一种循环参考(地图知道控制器和控制器知道地图)。这是个坏主意吗?

2 个答案:

答案 0 :(得分:6)

抽象父级JMapController包含JMapViewer构造函数传递给DefaultMapController的引用:

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

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

正如MVC outline中所建议的那样,给视图提供对控制器的引用是不常见的。相反,让控制器注册为视图的监听器没有任何问题,如here所示。

请注意,只有无参数JMapViewer构造函数会安装DefaultMapController。您可以使用备用构造函数,如Demo.java修订版29113中第57-59行的注释中所述。检查完整的示例here

答案 1 :(得分:1)

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

2)最好的事情是询问图书馆的维护者。无论如何,作为一般规则,我不打算改变任何东西,除非有充分的理由,例如,如果它明智地提高了可读性,而宁愿专注于真正的问题。

3)不确定是否是这种情况,但是,当您序列化JComponent时,还会序列化其所有字段。而且你不想序列化很多未使用过的东西。