带有匿名EventListener的JPanel - 为什么GC不销毁监听器? [英] JPanel with anonymous EventListener - why doesn't GC destroy listener?

查看:150
本文介绍了带有匿名EventListener的JPanel - 为什么GC不销毁监听器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



简而言之,主类是 JMapViewer ,它是 JPanel 。还有另外一个非常重要的类,称为 DefaultMapController ,它充当主类的 MouseListener



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

  public JMapViewer(){
//其他的东西
新的DefaultMapController(this);

$ / code>

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

  public void setMovementMouseButton(int movementMouseButton){
//更改用于移动地图的鼠标按钮
}

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



但是,我想到了更奇怪的东西!如果这个匿名实例的监听器没有引用,为什么它甚至能够存活? GC不应该很快摧毁它吗?或者GC足够聪明地知道引用实况 JComponent 的监听器类也必须保持活动状态才能正常工作,即使由于某种奇怪的原因而没有名称


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

我想贡献给这个开源库,我的第一个想法是更改 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行的注释中所述。 此处是一个完整的示例。


I have been perusing the open source code of JMapViewer. If anyone else wishes to look at it, check the SVN.

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.

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.

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:

  • why does GC not destroy object?
  • is this indeed a poor design choice, or is there some way I'm unaware of to access the controller from the class which instantiates the viewer?

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.


EDIT:

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?

解决方案

The abstract parent, JMapController, holds a reference to the JMapViewer passed there by the DefaultMapController constructor:

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

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.

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.

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.

这篇关于带有匿名EventListener的JPanel - 为什么GC不销毁监听器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆