2

我已经为一组通用侦听器实现了抽象通用提供程序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

什么是最好的解决方案?

  1. 使用另一个非 hashCode 支持集合——但WeakHashMap对我来说太棒了,因为自动为我管理弱引用

  2. 使用非通用监听器,例如具有简单equals() { return (this == object); }实现的抽象类——但这不是那么灵活

  3. addListener(E)使用简单的 equals() 为侦听器使用一些包装器——但由于弱引用,此包装器对调用者不能透明

另一个想法?

4

2 回答 2

4

WeakHashMap有点坏了。它使用弱密钥,但不使用身份哈希。除非您的密钥类型的equals()andhashCode()使用“身份”,否则您不应该使用WeakHashMap. 相反,您需要的东西是WeakHashMap和的组合IdentityHashMap

一种可能性是使用Google Collections 中的MapMaker。如果密钥很弱或很软,它会自动对密钥使用身份哈希/相等性。例如:

ConcurrentMap<K, V> myMap = new MapMaker().weakKeys().makeMap();
于 2009-11-10T19:26:01.733 回答
1

问题的症结似乎在于您的侦听器实现是子类化AbstractList,而不是覆盖equals()/ hashCode()。我强烈建议不要使用这种类型的继承(实现继承),因为它违反了 OO 原则(多态可替换性原则)。

实现一个自定义侦听器类会好得多,AbstractList如果它需要一个,它可能会引用一个,并且还提供它自己的equals()hashCode()实现。

于 2009-11-10T18:13:43.667 回答