1.实现原理:
HashMap的底层实现是一个哈希表即数组+链表;
HashMap初始容量大小16,扩容因子为0.75,扩容倍数为2;
HashMap本质是一个一定长度的数组,数组中存放的是链表。
HashMap初始容量大小16,扩容因子为0.75,扩容倍数为2;
HashMap本质是一个一定长度的数组,数组中存放的是链表。

HashMap的get(key)方法是:首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。从这里我们可以想象得到,如果每个位置上的链表只有一个元素,那么hashmap的get效率将是最高的。所以我们需要让这个hash算法尽可能的将元素平均的放在数组中每个位置上。
2.扩容机制
[Java]
纯文本查看
复制代码
1 2 3 4 5 6 | static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // HashMap初始容量大小(16) static final int MAXIMUM_CAPACITY = 1 << 30; // HashMap最大容量transient int size; // The number of key-value mappings contained in this mapstatic final float DEFAULT_LOAD_FACTOR = 0.75f; // 负载因子HashMap的容量size乘以负载因子[默认0.75] = threshold; // threshold即为开始扩容的临界值transient Entry<K,V>[] table = (Entry<K,V>[]) EMPTY_TABLE; // HashMap的基本构成Entry数组 |
当HashMap中的元素个数超过数组大小(数组总大小length,不是数组中个数size)*loadFactor时,就会进行数组扩容,loadFactor的默认值为0.75,这是一个折中的取值。也就是说,默认情况下,数组大小为16,那么当HashMap中元素个数超过16*0.75=12(这个值就是代码中的threshold值,也叫做临界值)的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置。
0.75这个值成为负载因子,那么为什么负载因子为0.75呢?这是通过大量实验统计得出来的,如果过小,比如0.5,那么当存放的元素超过一半时就进行扩容,会造成资源的浪费;如果过大,比如1,那么当元素满的时候才进行扩容,会使get,put操作的碰撞几率增加。
HashMap中扩容是调用resize()方法,方法源码:
[Java]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; //如果当前的数组长度已经达到最大值,则不在进行调整 if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //根据传入参数的长度定义新的数组 Entry[] newTable = new Entry[newCapacity]; //按照新的规则,将旧数组中的元素转移到新数组中 transfer(newTable); table = newTable; //更新临界值 threshold = (int)(newCapacity * loadFactor);}//旧数组中元素往新数组中迁移void transfer(Entry[] newTable) { //旧数组 Entry[] src = table; //新数组长度 int newCapacity = newTable.length; //遍历旧数组 for (int j = 0; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null) { src[j] = null; do { Entry<K,V> next = e.next; int i = indexFor(e.hash, newCapacity);//放在新数组中的index位置 e.next = newTable;//实现链表结构,新加入的放在链头,之前的的数据放在链尾 newTable = e; e = next; } while (e != null); } }} |
可以看到HashMap不是无限扩容的,当达到了实现预定的MAXIMUM_CAPACITY,就不再进行扩容。