带有匿名 EventListener 的 JPanel - 为什么 GC 不销毁侦听器?
我一直在阅读 JMapViewer 的开源代码.如果其他人希望查看它,请查看 SVN.
I have been perusing the open source code of JMapViewer. If anyone else wishes to look at it, check the SVN.
简而言之,主类是JMapViewer
,它是JPanel
的扩展.还有一个非常重要的类叫做DefaultMapController
,它作为主类的MouseListener
.
In a nutshell, the main class is JMapViewer
, which is an extension of a JPanel
. There is another very important class called DefaultMapController
which acts as a MouseListener
for the main class.
我注意到的第一件奇怪的事情是查看器没有对控制器的引用.JMapViewer
构造函数实例化 DefaultMapController
的匿名实例,如下所示:
The first weird thing I noticed is that the viewer has no references to the controller. The JMapViewer
constructor instantiates an anonymous instance of the DefaultMapController
, like this:
public JMapViewer() {
// other stuff
new DefaultMapController(this);
}
在我看来,这似乎是一个糟糕的设计选择,因为控制器有大量的方法(选项、切换等 - 示例如下所示),现在根本无法访问,那么它们有什么好处?
This seems to me to be a poor design choice, since the controller has tons of methods (options, toggles, etc - example shown below), which now can not be accessed at all, so what good are they?
public void setMovementMouseButton(int movementMouseButton) {
// changes which mouse button is used to move the map
}
控制器确实具有对查看器的引用,如上面的第一个片段所示,这就是它能够行使控制的方式.
The controller does have a reference to the viewer as shown in the first snippet above, which is how it is able to exercise control.
然而,我想到了更奇怪的事情!如果侦听器的这个匿名实例没有引用,为什么还要允许它存活呢?GC不应该快速销毁它吗?或者 GC 是否足够聪明,可以知道引用活动 JComponent
的侦听器类也必须保持活动状态才能正常工作,即使由于某种奇怪的原因它没有名称?
However, then I thought of something even weirder! If this anonymous instance of the listener has no references, why is it allowed to even survive? Shouldn't the GC destroy it quickly? Or is GC smart enough to know that a listener class which references a live JComponent
must also stay alive to work properly, even if it has no name for some strange reason?
那么,两个真正的问题:
So, two real questions:
- 为什么 GC 不销毁对象?
- 这确实是一个糟糕的设计选择,还是我不知道有什么方法可以从实例化查看器的类中访问控制器?
我想为这个开源库做贡献,我的第一个想法是更改 JMapViewer
类,使其具有引用其控制器的字段,并更改构造函数以分配当前这个新字段的匿名控制器.但是,我想确保我不会无知地遗漏一些东西.我已经在整个代码库中搜索了文本 DefaultMapController
,它只出现在它自己的类定义中,以及 JMapViewer
构造函数中的匿名实例中.
I want to contribute to this open source library, and my first idea for a change is to change the JMapViewer
class to have a field referencing its controller, and to change the constructor to assign the currently anonymous controller to this new field. But, I want to make sure I'm not ignorantly missing something. I have searched the entire codebase for the text DefaultMapController
, and it only occurs in its own class definitions, and in the anonymous instantiations in the JMapViewer
constructors.
确实似乎有一种方法可以访问匿名侦听器,方法是使用 java.awt.Component
方法 getMouseListeners()
.所以从技术上讲,在我的应用程序中,我可以在这个集合中搜索 DefaultMapController
的实例,并使用它来访问我需要用来更改控制器选项的方法.
It does indeed appear that there is a way to access the anonymous listeners, by using the java.awt.Component
method getMouseListeners()
. So technically in my application I could search this collection for instances of DefaultMapController
, and use that to access the methods I need to use to change the controller options.
不过,为了扮演魔鬼的拥护者,如果我按照最初的想法为地图提供其控制器的引用,现在我有一种循环引用(地图知道控制器,控制器知道地图).这是个坏主意吗?
To play devil's advocate though, if I go with original idea and give the map a reference of its controller, now I have a sort of circular reference (map knows of controller and controller knows of map). Is this a bad idea?
推荐答案
抽象父级 JMapController
持有由 传递的
构造函数:JMapViewer
的引用DefaultMapController
The abstract parent, JMapController
, holds a reference to the JMapViewer
passed there by the DefaultMapController
constructor:
public DefaultMapController(JMapViewer map) {
super(map);
}
附录:控制器持有的 map
引用用于(有选择地)将最多三个控制器引用添加到地图的 EventListenerList
,讨论了 这里.其中任何一项都会排除 GC.至少一个有益的设计好处是具体的 JMapController
只需要实现可用的接口.
Addendum: The map
reference held by the controller is used to (selectively) add up to three controller references to the map's EventListenerList
, discussed here. Any one of these would preclude GC. At least one salutary design benefit is that a concrete JMapController
need only implement available interfaces.
正如 MVC 大纲 中所建议的,给视图提供对控制器的引用是不寻常的.相比之下,按照此处的建议,让控制器注册为视图的侦听器并没有什么问题.
As suggested in this MVC outline, it would be unusual to give the view a reference to the controller. In contrast, there's nothing wrong with letting the controller register as a listener to the view, as suggested here.
请注意,只有无参数的 JMapViewer
构造函数会安装 DefaultMapController
.您可以使用备用构造函数,如 Demo.java
修订版 29113 中第 57-59 行的注释中所述.这里查看了一个完整的示例.
Note that only the no-argument JMapViewer
constructor installs a DefaultMapController
. You can use the alternate constructor, as noted in comments at line 57-59 in revision 29113 of Demo.java
. A complete example is examined here.
相关文章