5.1、对于HashMap需要掌握以下几点
- Map的创建:HashMap()
- 往Map中添加键值对:即put(Object key, Object value)方法
- 获取Map中的单个对象:即get(Object key)方法
- 删除Map中的对象:即remove(Object key)方法
- 判断对象是否存在于Map中:containsKey(Object key)
- 遍历Map中的对象:即keySet(),在实际中更常用的是增强型的for循环去做遍历
- Map中对象的排序:主要取决于所采取的排序算法
5.2、构建HashMap
源代码:
一些属性:
static final int DEFAULT_INITIAL_CAPACITY = 16; // 默认的初始化容量(必须是2的多少次方) static final int MAXIMUM_CAPACITY = 1 << 30; // 最大指定容量为2的30次方 static final float DEFAULT_LOAD_FACTOR = 0.75f; // 默认的加载因子(用于resize) transient Entry[] table;// Entry数组(数组容量必须是2的多少次方,若有必要会扩容resize)--这就是HashMap的底层数据结构 transient int size; // 该map中存放的key-value对个数,该个数决定了数组的扩容(而非table中的所占用的桶的个数来决定是否扩容) // 扩容resize的条件:eg.capacity=16,load_factor=0.75,threshold=capacity*load_factor=12,即当该map中存放的key-value对个数size>=12时,就resize) int threshold; final float loadFactor; // 负载因子(用于resize) transient volatile int modCount;// 标志位,用于标识并发问题,主要用于迭代的快速失败(在迭代过程中,如果发生了put(添加而不是更新的时候)、remove操作,该值发生变化,快速失败)
注意:
- map中存放的key-value对个数size,该个数决定了数组的扩容(size>=threshold时,扩容),而非table中的所占用的桶的个数来决定是否扩容
- 标志位modCount采用volatile实现该变量的线程可见性(之后会在"Java并发"章节中去讲)
- 数组中的桶,指的就是table[i]
- threshold默认为0.75,这是综合时间和空间的利用率来考虑的,通常不要变,如果该值过大,可能会造成链表太长,导致get、put等操作缓慢;如果太小,空间利用率不足。
无参构造器(也是当下最常用的构造器)
/** * 初始化一个负载因子、resize条件和Entry数组 */ public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR;// 负载因子:0.75 threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);//当该map中存放的key-value对个数size>=12时,就resize table = new Entry[DEFAULT_INITIAL_CAPACITY];// 设置Entry数组容量为16 init(); }
注意:
- init()为空方法
对于hashmap而言,还有两个比较常用的构造器,一个双参,一个单参。
/** * 指定初始容量和负载因子 */ public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity:"+initialCapacity); if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor))//loadFactor<0或者不是一个值 throw new IllegalArgumentException("Illegal load factor:"+loadFactor); /* * 下边的逻辑是找一个2的几次方的数,该数刚刚大于initialCapacity * eg.当指定initialCapacity为17,capacity就是32(2的五次方),而2的四次方(16)正好小于17 */ int capacity = 1; while (capacity < initialCapacity) capacity <<= 1;// capacity = capacity<<1 this.loadFactor = loadFactor; threshold = (int)(capacity * loadFactor); table = new Entry[capacity]; init(); } /** * 指定初始容量 */ public HashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR);//调用上边的双参构造器 }