我已经为通用侦听器E
的通知束实现了抽象通用提供程序,后代必须使用特定的通知代码覆盖notifyListener(E)
。对于收听者的后备列表,我选择WeakHashMap<K,V>
。侦听器必须作为弱引用:
abstract public class NotificationProvider<E> {
private Map<E, Object> listeners = new WeakHashMap<E, Object>();
public addListener(E listener) {
listeners.put(listener, null);
}
public void notifyListeners() {
for (E listener: listeners.keySet())
notifyListener(listener);
}
abstract protected void notifyListener(E listener);
}
典型用途:
NotificationProvider<MyListener> provider;
provider = new NotificationProvider<MyListener>() {
@Override
protected void notifyListener(MyListener listener) {
listener.myNotification();
}
}
provider.addListener(myListener1);
provider.addListener(myListener2);
provider.notifyListeners();
一切正常,但是当我需要
AbstractList
后代类作为侦听器时,支持WeakHashMap
仅接受一个侦听器实例!很明显-侦听器上的方法hashCode()
和equals()
对于所有实例(空列表)返回相同的值,因此WeakHashMap.put
仅替换先前添加的侦听器。 public class MyList extends AbstractList<MyItem> {
// some implementation
}
NotificationProvider<MyList> provider;
provider = new NotificationProvider<MyList>() {
@Override
protected void notifyListener(MyList listener) {
// some implementation
}
}
MyList list1 = new MyList();
MyList list2 = new MyList();
provider.addListener(list1);
provider.addListener(list2);
provider.notifyListeners(); // only list2 instance is notified
最好的解决方案是什么?
使用另一个非hashCode支持集合-但是
WeakHashMap
对我来说是如此甜蜜,因为自动为我管理弱引用使用非泛型侦听器,例如具有简单
equals() { return (this == object); }
实现的抽象类-但这不是那么灵活对带有简单equals()的侦听器使用一些包装器-但是由于弱引用,此包装器对于
addListener(E)
调用者不能透明还有其他想法吗?
最佳答案
WeakHashMap
有点坏。它使用弱键,但不使用身份哈希。除非键类型的equals()
和hashCode()
使用“身份”,否则不应该使用WeakHashMap
。相反,您需要的是WeakHashMap
和IdentityHashMap
的组合。
一种可能性是使用Google收藏夹中的MapMaker。如果密钥较弱或较弱,它将自动对密钥使用身份哈希/相等性。例如:
ConcurrentMap<K, V> myMap = new MapMaker().weakKeys().makeMap();