一尘不染

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

javascript

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

简而言之,主要类是JMapViewer,这是a的扩展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该类以使其具有引用其控制器的字段,并更改构造函数以将当前匿名控制器分配给该新字段。但是,我想确保我不会无所遗漏。我已经在整个代码库中搜索了text DefaultMapController,并且它仅出现在其自己的类定义中以及JMapViewer构造函数中的匿名实例中。

编辑:

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

不过,要扮演魔鬼的拥护者,如果我坚持最初的想法,并给地图提供其控制器的参考,那么现在我有了一种循环参考(地图知道控制器,而控制器也知道地图)。这是一个坏主意吗?


阅读 312

收藏
2020-09-17

共1个答案

一尘不染

抽象的父,JMapController拥有构造函数JMapViewer传递给它的引用DefaultMapController

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

附录:map由控制器保存的参考用于(有选择地)将最多三个控制器参考加到地图上EventListenerList,在此进行讨论。这些中的任何一个都将排除GC。至少一个有益的设计好处是,具体JMapController只需实现可用的接口。

正如在此MVC大纲中所建议的那样,给视图提供对控制器的引用是不寻常的。与此相反,没有什么错,让控制器寄存器作为监听器的观点,所建议的在这里。

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

2020-09-17