我已经为通用侦听器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。相反,您需要的是WeakHashMapIdentityHashMap的组合。

一种可能性是使用Google收藏夹中的MapMaker。如果密钥较弱或较弱,它将自动对密钥使用身份哈希/相等性。例如:

ConcurrentMap<K, V> myMap = new MapMaker().weakKeys().makeMap();

10-07 13:13