听众作为弱点的利弊

pde*_*eva 70 java design-patterns weak-references observer-pattern

将听众保持为WeakReferences的利弊是什么.

当然,最大的'专业'是:

将侦听器添加为WeakReference意味着侦听器不需要打扰"删除"自身.

更新

对于那些担心只有对象引用的侦听器,为什么有2个方法,addListener()和addWeakRefListener()?

那些不关心去除的人可以使用后者.

Beg*_*moT 69

首先,在侦听器列表中使用WeakReference将为您的对象提供不同的语义,然后使用硬引用.在硬引用的情况下,addListener(...)表示" 通过removeListener(..)显式停止它,直到通知提供的对象",在弱引用的情况下,它意味着"通知提供的对象有关特定事件( s)直到此对象不被其他任何人使用(或使用removeListener明确停止)".请注意,在许多情况下,拥有对象,侦听某些事件以及没有其他引用来保留GC是完全合法的.记录器就是一个例子.

正如你所看到的,使用WeakReference不仅仅解决了一个问题("我应该记住不要忘记在某个地方删除添加的监听器"),还要提出另一个问题 - "我应该记住,我的听众可以停止听任何没有任何参考的时刻".你没有解决问题,你只是将一个问题换成另一个问题.看,无论如何,你不得不以某种方式清楚地定义,设计和追踪你的听众的活跃.

所以,就个人而言,我同意提及在侦听器列表中使用WeakReference更像是一个hack而不是一个解决方案.例如,值得了解的模式,有时它可以帮助您 - 使遗留代码运行良好.但它不是选择的模式:)

PS还应该注意WeakReference引入了额外的间接级别,在某些情况下具有极高的事件率,可能会降低性能.

  • 使用WeakReference的另一个问题 - "我应该记住,我的监听器引起的任何状态变化可能仍然在它超出范围之后发生".因此,WeakReference Listener需要在知道其存在是非确定性的情况下进行设计. (3认同)

Kir*_*oll 31

这不是一个完整的答案,但你引用的力量也可能是它的主要弱点.考虑如果动作侦听器被弱化地实现会发生什么:

button.addActionListener(new ActionListener() {
    // blah
});
Run Code Online (Sandbox Code Playgroud)

那个动作监听器随时都会收集垃圾!对匿名类的唯一引用是您要添加它的事件并不罕见.

  • @pdeva,我不是说维护这个原则是坏事.但我相信这种药至少和症状一样糟糕 - 如果他们忘记正确使用药物(用错误的方法添加听者),他们的形状将比正常的解决方案更糟糕. (6认同)
  • “防止健忘的程序员犯错误。” 这不是GC被发明的原因吗?:) 此外,它使您的代码更简单,因为您不必记住在处理对象时删除侦听器。 (2认同)

Jér*_*nge 10

我已经看到大量的代码,其中侦听器未正确注销.这意味着他们仍然被不必要地执行不必要的任务.

如果只有一个类依赖于一个监听器,那么它很容易清理,但是当25个类依赖它时会发生什么?正确注销它们变得更加棘手.事实上,您的代码可以从引用侦听器的一个对象开始,最终将在25个对象引用同一个侦听器的未来版本中结束.

不使用WeakReference相当于消耗不必要的内存和CPU的大风险.它更复杂,更棘手,并且需要在复杂代码中使用硬引用进行更多工作.

WeakReferences充满了专业人士,因为他们会自动清理.唯一的问题是你不能忘记在代码中的其他地方保留一个硬引用.通常,在依赖于此侦听器的对象中.

我讨厌创建监听器的匿名类实例的代码(如Kirk Woll所述),因为一旦注册,你就不能再注销这些监听器了.您没有对它们的引用.这是非常糟糕的编码恕我直言.

null当你不再需要它时,你也可以引用一个监听器.你不用再担心了.


Jam*_*ven 5

真的没有专业人士.弱参数通常用于"可选"数据,例如您不希望阻止垃圾回收的缓存.您不希望收集侦听器垃圾,您希望它继续收听.

更新:

好吧,我想我可能已经弄清楚你得到了什么.如果要向长期存在的对象添加短期监听器,则使用weakReference可能会有好处.因此,例如,如果您要将PropertyChangeListeners添加到域对象以更新不断重新创建的GUI的状态,则域对象将保留到可能构建的GUI.想象一下不断重新创建的大弹出对话框,通过PropertyChangeListener将侦听器引用回Employee对象.如果我错了,请纠正我,但我认为整个PropertyChangeListener模式不再受欢迎了.

另一方面,如果您正在谈论GUI元素之间的侦听器或者让域对象听取GUI元素,那么您将不会购买任何东西,因为当GUI消失时,侦听器也会消失.

这里有几个有趣的读物:

http://www.javalobby.org/java/forums/t19468.html

如何解决swing监听器内存泄漏?

  • “可选”数据(例如缓存)的正确引用类型是 SoftReference,而不是 WeakReference。WeakReference 通常用于防止引用泄漏,显式获得比 SoftReference 更高的最终确定优先级,这样它们就不会在 GC 扫描期间干扰缓存项的存储。 (2认同)

Nic*_*uet 5

老实说,我并不真正相信这个想法,也不完全相信您希望使用 addWeakListener 做什么。也许这只是我,但这似乎是一个错误的好主意。起初它很诱人,但它可能暗示的问题不容忽视。

使用weakReference,您不确定当不再引用侦听器本身时将不再调用侦听器。垃圾收集器可以在几毫秒后或永远不会释放内存。这意味着它可能会继续消耗 CPU 并像抛出异常一样奇怪,因为不应调用侦听器。

Swing 的一个例子是尝试做只有当您的 UI 组件实际上附加到活动窗口时才能做的事情。这可能会引发异常,并影响通知程序使其崩溃并阻止通知有效侦听器。

如前所述,第二个问题是匿名侦听器,他们可能会过早被释放,根本不会通知或只通知几次。

您试图实现的目标很危险,因为当您停止接收通知时,您将无法再控制。它们可能会永远持续下去,也可能停止得太早。