首页 > 代码库 > Java技术之HashMap

Java技术之HashMap

     哈希映像,它在Java中经常用到,主要保存key-value数据,其中HashMap实现了Map接口。系统通过Hash算法来计算key-value存储的位置,这样可以快速存取Map的key-value对。

HashMap的存储实现

HashMap采用一种所谓的“Hash 算法”来决定每个元素的存储位置。下面结合源码解析HashMap的实现。

HashMap<String, String> map=new HashMap<String, String>();
map.put("A", "Forsta");
map.put("B", "Sam");
map.put("C", "Jack");

HashMap通过put方法将key-value保存到hashmap中。

 1  public V put(K key, V value) { 2         if (key == null) 3             return putForNullKey(value); 4         int hash = hash(key.hashCode()); 5         int i = indexFor(hash, table.length); 6         for (Entry<K,V> e = table[i]; e != null; e = e.next) { 7             Object k; 8             if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 9                 V oldValue =http://www.mamicode.com/ e.value;10                 e.value =http://www.mamicode.com/ value;11                 e.recordAccess(this);12                 return oldValue;13             }14         }15 16         modCount++;17         addEntry(hash, key, value, i);18         return null;19     }

保存key-value具体的流程是,首先获取到key,判断key是否为null,如果为null,则直接将value保存到key=null处。如果所求key关键字已经存储在Hash表中,则覆盖当前位置。如果没有保存就直接添加一个Entry,插入表中。新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位于 Entry 链的头部。

否则首先计算key的hash值  获取key对象的hashCode---Hash算法---求得表索引值。

1  static int hash(int h) {2         h ^= (h >>> 20) ^ (h >>> 12);3         return h ^ (h >>> 7) ^ (h >>> 4);4     }
1  static int indexFor(int h, int length) {2         return h & (length-1);3     }

这个方法非常巧妙,它总是通过 h &(table.length -1) 来得到该对象的保存位置。table.length-1保证返回索引小于表长,一定位于表中。

1 void addEntry(int hash, K key, V value, int bucketIndex) {2         Entry<K,V> e = table[bucketIndex];3         table[bucketIndex] = new Entry<>(hash, key, value, e);4         if (size++ >= threshold)5             resize(2 * table.length);6     }

addEntry方法,将新插入的Entry放到数组表中,如果之前表中已经有Entry数据了,则将新添加的Entry对象next指向原来的对象,形成Entry链;如果没有,则指向空。

如果数据超过threshold值,则进行扩容,但每次都原来的2倍。

HashMap具体的结构如下图

HashMap 的读取实现 

     当 HashMap 的每个 bucket 里存储的 Entry 只是单个 Entry ——也就是没有通过指针产生 Entry 链时,此时的 HashMap 具有最好的性能:当程序通过 key 取出对应 value 时,系统只要先计算出该 key 的 hashCode() 返回值,在根据该 hashCode 返回值找出该 key 在 table 数组中的索引,然后取出该索引处的 Entry,最后返回该 key 对应的 value 即可。看 HashMap 类的 get(K key) 方法代码: 

 1  public V get(Object key) { 2         if (key == null) 3             return getForNullKey(); 4         int hash = hash(key.hashCode()); 5         for (Entry<K,V> e = table[indexFor(hash, table.length)]; 6              e != null; 7              e = e.next) { 8             Object k; 9             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))10                 return e.value;11         }12         return null;13     }