收藏地图

时间:2008-10-31 17:47:51

标签: java generics collections

我想在Java中创建集合地图,所以我可以制作像

这样的东西
public void add(K key, V value) {  
    if (containsKey(key)) {
        get(key).add(value);
    } else {
        Collection c = new Collection();
        c.add(value);
        put(key, value);
    }
}

我试图用类似

的东西来制作它
public class CollectionMap<K, C extends Collection<V>> extends HashMap<K, C>

但是编译器抱怨<V>部分,并且仍然存在制作正确的新集合的问题。

目前,我已经制作了两个类:SetMap,看起来像这样

 1: public class SetMap<K, V> extends HashMap<K, Set<V>> {
 2: 
 3:    public void add(K key, V value) {
 4:        if (containsKey(key)) {
 5:            get(key).add(value);
 6:        } else {
 7:            Set<V> list = new HashSet<V>();
 8:            list.add(value);
 9:            put(key, list);
10:        }
11:    }
12:
13: }

和ListMap看起来几乎相同,除了我创建新ArrayList的第7行。这种重复小到可以容忍,但问题仍然存在于Java中这种“嵌套泛型”可能吗?

编辑:

作为erickson said,解决方案位于<A, B extends Something<A>>而非<B extends Something<A>>

因此代码看起来像

public abstract class CollelctionMap<K, V, C extends Collection<V>> extends HashMap<K, C> {

    protected abstract C newCollection();

    public void add(K key, V value) {
        if (containsKey(key)) {
            get(key).add(value);
        } else {
            C c = newCollection();
            c.add(value);
            put(key, c);
        }
    }
}

和ListMap和SetMap只提供适当的集合

5 个答案:

答案 0 :(得分:11)

如果mapMap<K, Collection<V>>,请使用这样的成语computeIfAbsent(...).add(...),

map.computeIfAbsent(key, k -> new ArrayList<>()).add(value);

或者,对于Set

map.computeIfAbsent(key, k -> new HashSet<>()).add(value);

答案 1 :(得分:6)

如果是一个选项,您可能只想使用Google Collections API - http://code.google.com/p/google-collections/

即使你不能使用它,也许看看他们如何实现他们的MultiMaps将帮助你实现。

答案 2 :(得分:2)

您的代码存在问题:

收藏c = new Collection();

无法实例化。

我认为下一段代码可以解决您的问题:

public class CollectionMap<K, V> extends HashMap<K, Collection<V>> {


    ...
    ...
    ...


    public void add(K key, V value) {
        if (containsKey(key)) {
            get(key).add(value);
        } else {
            Collection<V> c = new ArrayList<V>();
            c.add(value);
            super.put(key, c);
        }
    }
}

答案 3 :(得分:2)

Apache Commons Collections也提供了一个MultiMap,但它是JDK之前的1-.5,所以你没有那里的泛型安全性。您可以将它包装在Collections.checkedMap(Key.class,Value.class,collection)中以确保运行时安全。如果您可以使用Google的Colelction API,它可以提供更加流畅的MultiMap,包括所有的泛型,铃声和口哨声。

答案 4 :(得分:2)

如果可能,请使用Google的Guava。伙计们在那里做得非常好。

这是另一种解决方案。

abstract class MultiMap<K, V> {

    private Map<K, Collection<V>> entries = new LinkedHashMap<K, Collection<V>>();

    public void put(K key, V value) {
        Collection<V> values = entries.get(key);
        if (values == null) {
            entries.put(key, values = newValueCollection());
        }
        values.add(value);
    }

    // other methods
    // ..

    abstract Collection<V> newValueCollection();



    // Helper methods to create different flavors of MultiMaps

    public static <K, V> MultiMap<K, V> newArrayListMultiMap() {
        return new MultiMap<K, V>() {
            Collection<V> newValueCollection() {
                return new ArrayList<V>();
            }
        };
    }

    public static <K, V> MultiMap<K, V> newHashSetMultiMap() {
        return new MultiMap<K, V>() {
            Collection<V> newValueCollection() {
                return new HashSet<V>();
            }
        };
        }

 }

您可以像

一样使用它
MultiMap<String, Integer> data = MultiMap.newArrayListMultiMap();
data.put("first", 1);
data.put("first", 2);
data.put("first", 3);