我一直在细读JMapViewer的开源代码.如果其他人想查看它,请检查 SVN .
简而言之,主类是JMapViewer
,它是一个JPanel
的扩展。还有另一个非常重要的类 DefaultMapController
,它充当主类的 MouseListener
。
我注意到的第一件奇怪的事情是查看器没有对 Controller 的引用。 JMapViewer
构造函数实例化了 DefaultMapController
的匿名实例,如下所示:
public JMapViewer() {
// other stuff
new DefaultMapController(this);
}
在我看来,这似乎是一个糟糕的设计选择,因为 Controller 有大量的方法(选项、切换等 - 示例如下所示),现在根本无法访问,那么它们有什么用呢?
public void setMovementMouseButton(int movementMouseButton) {
// changes which mouse button is used to move the map
}
Controller 确实有对查看器的引用,如上面第一个片段所示,这就是它能够行使控制权的方式。
不过,后来我想到了更奇怪的事情!如果监听器的这个匿名实例没有引用,为什么允许它生存呢? GC 不应该迅速销毁它吗?或者 GC 是否足够聪明,知道引用 Activity JComponent
的监听器类也必须保持 Activity 状态才能正常工作,即使它出于某种奇怪的原因没有名称也是如此?
那么,两个真正的问题:
- 为什么 GC 不销毁对象?
- 这确实是一个糟糕的设计选择,还是我不知道有什么方法可以从实例化查看器的类访问 Controller ?
我想为这个开源库做贡献,我的第一个改变想法是改变 JMapViewer
类,让它有一个字段引用它的 Controller ,并改变构造函数来分配当前这个新领域的匿名 Controller 。但是,我想确保我没有无知地遗漏一些东西。我在整个代码库中搜索了文本 DefaultMapController
,它只出现在它自己的类定义中,以及 JMapViewer
构造函数中的匿名实例中。
编辑:
看来确实有一种方法可以访问匿名监听器,方法是使用 java.awt.Component
方法 getMouseListeners()
。所以从技术上讲,在我的应用程序中,我可以在这个集合中搜索 DefaultMapController
的实例,并使用它来访问我需要用来更改 Controller 选项的方法。
尽管唱反调,如果我坚持最初的想法并为 map 提供其 Controller 的引用,那么现在我有一种循环引用( map 知道 Controller , Controller 知道 map )。这是个坏主意吗?
最佳答案
抽象父类 JMapController
持有对 JMapViewer
的引用,由 DefaultMapController
构造函数传递给那里:
public DefaultMapController(JMapViewer map) {
super(map);
}
附录: Controller 持有的map
引用用于(有选择地)将最多三个 Controller 引用添加到 map 的EventListenerList
。 , 讨论 here .其中任何一个都会阻止 GC。至少一个有益的设计好处是具体的 JMapController
只需要实现可用的接口(interface)。
如本 MVC outline 中所建议, 给 View 一个 Controller 的引用是不寻常的。相比之下,让 Controller 注册为 View 的监听器并没有错,正如建议的那样here .
请注意,只有无参数的JMapViewer
构造函数会安装DefaultMapController
。您可以使用备用构造函数,如 Demo.java
修订版 29113 中第 57-59 行的注释中所述。检查了一个完整的示例 here .
关于java - 带有匿名 EventListener 的 JPanel - 为什么 GC 不破坏监听器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14016262/