HashMap解析以及使用
一、HashMap的数据结构
HashMap的数据结构是链表散列,即数组和链表的结合体。
数组:存储空间连续,空间复杂度高,便于查询,不便于插入和删除;
链表:存储空间离散,空间复杂度小,便于插入和删除,反而寻址困难不易查询;
二、底层源码实现
// 存储的源码
public V put(K key, V value) { // HashMap允许存放null键和null值。 // 当key为null时,调用putForNullKey方法,将value放置在数组第一个位置。 if (key == null) return putForNullKey(value); // 根据key的keyCode重新计算hash值。 int hash = hash(key.hashCode()); // 搜索指定hash值在对应table中的索引。 int i = indexFor(hash, table.length); // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素。 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } // 如果i索引处的Entry为null,表明此处还没有Entry。 modCount++; // 将key、value添加到i索引处。 addEntry(hash, key, value, i); return null; }
首先,根据key计算hash值,根据hash值得到这个元素在数组中的索引;如果数组中的这个位置上放了其他元素,那么在这个位置上的元素们以链表的方式存放。新加入的放入链头,最先加入的放入链尾。如果数组中的这个位置上没有放元素,直接放入即可。
addEntry(hash, key, value, i)方法根据计算出的hash值,将key-value对放在数组table的i索引处。addEntry 是 HashMap 提供的一个包访问权限的方法。
void addEntry(int hash, K key, V value, int bucketIndex) { // 获取指定 bucketIndex 索引处的 Entry Entry<K,V> e = table[bucketIndex]; // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry table[bucketIndex] = new Entry<K,V>(hash, key, value, e); // 如果 Map 中的 key-value 对的数量超过了极限 if (size++ >= threshold) // 把 table 对象的长度扩充到原来的2倍。 resize(2 * table.length); }
// 根据key获取元素
public V get(Object key) { if (key == null) return getForNullKey(); int hash = hash(key.hashCode()); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
从HashMap中get元素时,首先计算key的hashCode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。
喜欢请赞赏一下啦^_^
微信赞赏
![](https://images.cnblogs.com/cnblogs_com/ljf-Sky/1807277/o_200716012544%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20200716092510.jpg)
支付宝赞赏
![](https://images.cnblogs.com/cnblogs_com/ljf-Sky/1807277/o_200716012531%E5%BE%AE%E4%BF%A1%E5%9B%BE%E7%89%87_20200716092459.jpg)