您可以围绕 (Hash)Map 创建一个包装类,并装饰 put()-remove() 方法来维护另一个映射,其中原始 Map 的值是键,值是出现的次数。然后你只需要实现方法来查询......
然而,这相当棘手!您必须小心不要再链接到不在地图中的对象...这可能会导致内存泄漏!
此外,必须考虑空值容差......
public static class MyCountingMap<K,V> implements Map<K,V> {
private final Map<K,V> internalMap;
//hashmap tolerates null as a key!
private final Map<V,Long> counterMap = new HashMap<V, Long>();
public MyCountingMap(Map<K, V> internalMap) {
super();
this.internalMap = internalMap;
}
@Override
public V put(K key, V value) {
boolean containedOriginally = internalMap.containsKey(key);
V origValue = internalMap.put(key, value);
updateCounterPut(containedOriginally, origValue, value);
return origValue;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
//now this is the awkward part...
//this whole thing could be done through a loop and the put() method,
//but I'd prefer to use the original implementation...
for(Map.Entry<? extends K, ? extends V> entry :m.entrySet()) {
boolean containedOriginally = internalMap.containsKey(entry.getKey());
V origValue = internalMap.get(entry.getKey());
updateCounterPut(containedOriginally, origValue, entry.getValue());
}
internalMap.putAll(m);
}
// this method updates the counter
private void updateCounterPut(boolean containedOriginally, V origValue, V newValue) {
//if it was in the map, and it is different than the original, decrement
if(containedOriginally && isDifferent(origValue, newValue))
{
decrement(origValue);
}
//if it was NOT in the map, or the value differs
if(!containedOriginally || isDifferent(origValue, newValue)) {
increment(newValue);
}
}
// nothing special, just nicer to extract this to a method. Checks if the two values are the same or not.
private static boolean isDifferent(Object origValue, Object newValue) {
return ((origValue==null && newValue!=null) || !(origValue!=null && origValue.equals(newValue)));
}
//this method returns the counter value for the map value
public Long getValueCount(V value) {
return counterMap.get(value);
}
@Override
public V remove(Object key) {
V toReturn = internalMap.remove(key);
if(toReturn!=null) {
decrement(toReturn);
}
return toReturn;
}
private void increment(V value) {
Long count = counterMap.get(value);
if(count == null) {
count = 0L;
}
counterMap.put(value, count+1);
}
private void decrement(V value) {
Long count = counterMap.get(value);
if(count == null) {
count = 0L;
}
//last! Have to remove reference to prevent memory leak!!
if(count == 1L) {
counterMap.remove(value);
} else {
counterMap.put(value, count-1);
}
}
//... boring wrapper methods ...
public void clear() { internalMap.clear(); }
public boolean containsKey(Object key) { return internalMap.containsKey(key); }
public boolean containsValue(Object value) { return internalMap.containsValue(value); }
public Set<Entry<K, V>> entrySet() { return internalMap.entrySet(); }
public V get(Object key) { return internalMap.get(key); }
public boolean isEmpty() { return internalMap.isEmpty(); }
public Set<K> keySet() { return internalMap.keySet(); }
public int size() { return internalMap.size(); }
public Collection<V> values() { return internalMap.values(); }
}