ericchunli 阅读(14) 评论(0)

在实际的项目运用中有可能会遇到用Map处理单键多值的情形,以下为最常见的两种方式:

1.JDK7自带的处理方式

String key1 = new String("key");

String key2 = new String("key");

String key3 = "key";

String key4 = "key";

Map<String, String> map = new IdentityHashMap<String, String>();

map.put(key1, "eric_1");

map.put(key2, "eric_2");

map.put(key3, "eric_3");

map.put(key4, "eric_4");

for (Entry<String, String> entry : map.entrySet()) {

     System.out.println(entry.getKey() + "   " + entry.getValue());

}

源码分析:

public V put(K key, V value) {

        Object k = maskNull(key);

        Object[] tab = table;

        int len = tab.length;

        int i = hash(k, len);

        Object item;

        while ( (item = tab[i]) != null) {

            if (item == k) {

                V oldValue = (V) tab[i + 1];

                tab[i + 1] = value;

                return oldValue;

            }

            i = nextKeyIndex(i, len);

        }

        modCount++;

        tab[i] = k;

        tab[i + 1] = value;

        if (++size >= threshold)

            resize(len); 

        return null;

    }

由源码可以看出它的底层实现就是在数组中的不同的位置保存对应的值。其实JDK自带的方法是存在一定的局限性,它不能够保证单键多值的实现。如果Key是相同的对象会导致后插入的值覆盖以前插入的值,如果要保证单键多值的实现得确保所保存的键值是不同的对象。

2.第三方提供的方法

#Multimap<String, String> myMultimap = ArrayListMultimap.create();

MultiValueMap<String, String> stringMultiValueMap = new LinkedMultiValueMap<>();

stringMultiValueMap.add("name", "eric");

stringMultiValueMap.add("name", "li");

stringMultiValueMap.add("name", "bob");

stringMultiValueMap.add("name", "lic");

stringMultiValueMap.add("domain", "http://www.baidu.com");

stringMultiValueMap.add("domain", "http://www.tudou.com");

Set<String> keySet = stringMultiValueMap.keySet();

for (String key : keySet) {

   List<String> values = stringMultiValueMap.get(key);

   for (String value : values) {

      System.out.println(key + ": " + value);

   }

}

源码分析(Spring):

  private final Map<K, List<V>> targetMap;

  public LinkedMultiValueMap()

  {

    targetMap = new LinkedHashMap();

  }

   public void add(K key, V value)

   {

     List<V> values = (List)targetMap.get(key);

     if (values == null) {

      values = new LinkedList();

      targetMap.put(key, values);

     }

     values.add(value);

  }

源码分析(Guava):

public static <K, V> ArrayListMultimap<K, V> create() {

    return new ArrayListMultimap<K, V>();

  }

  private ArrayListMultimap() {

    super(new HashMap<K, Collection<V>>());

    expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;

  }

@Override

  public boolean put(@Nullable K key, @Nullable V value) {

    Collection<V> collection = map.get(key);

    if (collection == null) {

      collection = createCollection(key);

      if (collection.add(value)) {

        totalSize++;

        map.put(key, collection);

        return true;

      } else {

        throw new AssertionError("New Collection violated the Collection spec");

      }

    } else if (collection.add(value)) {

      totalSize++;

      return true;

    } else {

      return false;

    }

  }

由Spring源码可以看出它的底层是由LinkedList和LinkedHashMap实现的,由Guava源码可以看出它的底层是由HashMap和Collection实现的。实际上无论是Spring源码的实现还是Guava源码的实现,都是JDK中Map的简单运用。

总结:无论是JDK自带的方法也好还是第三方提供的方法也罢,其实都是HashMap的简单运用。HashMap的源码实现由于JDK7和JDK8的差异,此处不作讨论。