一、Map 接口概述
Map 中存放键值对的 key 是唯一的,value 是可以重复的;
Map 中的 key 可以全部分离出来,存储到 Set 中来进行访问 (因为 key 不能重复);
Map 中的 value 也可以全部分离出来,存储在 Collection 集合中 ( value 可能有重复);
Map中键值对的 key不能直接修改,value 可以修改,如果要修改 key,只能先将该 key 删除掉,然后再来进行重新插入。
Map 接口常用方法:
二、Map.Entry<K, V>
Map.Entry 是 Map 内部实现的用来存放键值对映射关系的内部类(实际是接口),该内部类中主要提供了<key, value> 的获取,value 的设置以及 key 的比较方式。方法为:
三、HashMap
HashMap 中的 key 和 value 都可以为空,key 不能重复,是线程不安全的。
底层数据结构:数组 + 链表 / 红黑树(JDK 1.8及以后)
常用构造方法:
1. 构造一个空的 HashMap 对象,初始容量为16,加载因子为 0.75;
2. 构造一个空的 HashMap 对象,初始容量为指定的容量(第一个大于指定容量的二次幂),加载因子为 0.75;
4. 构造一个包含实现了 Map 接口的子类的 HashMap 对象;
HashMap 使用懒加载,在进行第一次 put 操作时才会初始化 table(在没有进行 put 操作的时候 table 为 null );
常用其他方法:
1. put(K key, V value):存放 key,value 键值对;
1)首先根据 hash() 方法计算 key 对应的 hash值;
2)调用 putVal() 方法来进行插入;
a. 首先会判断 table 是否为空(第一次 put 的时候),通过resize() 方法来进行初始化;默认容量大小为16,加载因子为 0.75;即当 table 中的数据达到此时的最大容量 16 * 0.75 = 12 时,会触发扩容机制,默认扩容为原来最大容量的 2 倍;
b. 判断是否产生冲突,根据由 key 计算的 hash 值在 node 数组中对应位置是否有元素来判断;
1. 如果没有元素,则直接在创建一个新的节点存放在 node 数组中;
2. 如果有元素,判断 key 计算的 hash 以及 通过 == 判断或者 equals 判断 key 是否都相等(与 table数组索引位置处的值判断);如果相等说明此时插入的 key 是重复的,替换掉原来的 value;
3. 如果经过 2 判断不成立,此时会判断当前数组位置上对应的节点类型是否为 TreeNode(即判断当前链表是否已经树化),如果已经树化了,则按照红黑树的插入执行;
4. 经 3 判断过之后,说明此时链表还没有树化,则会遍历该数组位置上的链表,
a:判断链表上的每个节点和当前要插入的节点的 key 算出的 hash 值是否相等,
b:并且 key 相等或者通过 equals 判断相等,如果都判断相等,则跳出循环,不再添加新节点(对应第二个 if 判断);
否则(对应第一个 if 判断),会创建一个新的节点(将其key,value等值赋值到新节点上)插入到链表的最后;插入完成后,判断是否达到树化的条件(数组长度大于等于 64 并且某一条链表的长度大于等于 8),若满足条件,则进行树化;
最后的 if 判断,进行 value 值的替换。
c. 最后插入完成后,判断是否达到了扩容的条件(table 中的总数据量达到临界值即 最大容量 * 加载因子),来决定是否需要进行扩容(通过 resize 方法扩容);
2. get(K key):根据 key 获取 value
通过调用 getNode 方法实现
1)首先判断 table 数组不为空,并且 table 数组的长度 不为 0,并且通过 hash 算法计算出 key 在table 表中的位置不为空,若不满足以上条件,则直接返回 null,也就是说 key 是不存在的;(对应第一个 if )
2)满足 1 之后,(对应第二个 if )
a:判断该 key 的hash值与 key 在 table 数组中对应位置的链表的第一个元素计算的 hash值 是否相等,
b: 通过 == 判断的 key 相等 或者 通过 equals 方法判断相等,
若满足 a 和 b,则说明该 table 数组位置上的链表的第一个节点就是要查询的节点;
3)不满足 2 之后,判断 这个链表的下一个节点是否为空,(对应第三个 if )
a:如果为空,说明链表只有一个节点并且不满足,则返回空,
b:如果不为空,判断其类型是否为 TreeNode,即判断是否已经树化(对应第四个 if ),若树化,则按照红黑树的方式进行查询,如果不为 TreeNode,则循环判断该链表上的每个节点是否满足 2 的条件,若满足则返回该节点,否则,一直判断直到该节点为 null;
3. containsKey(Object key)(通过getNode 方法判断)
4. 其他常用方法在 Map 接口常用方法 中;
四、TreeMap
TreeMap 中的 key 不可以为空,value 可以为 null,key 不能重复,是线程不安全的。
底层使用红黑树,查询的时间复杂度为 O (logn)
常用构造方法:
1. 创建一个空的 TreeMap 对象,使用其 key 的自然排序规则排序;
2. 创建一个空的 TreeMap 对象,使用指定的比较器进行排序;
3. 创建一个TreeMap 对象,其包含一个实现了 Map 接口的类的对象,使用 key 的自然排序规则排序;
其他常用方法:
1. Comparator<? super K> comparator():返回该映射中用于排序的比较器对象,若使用自然排序则返回 null;
2. 其他常用方法在 Map 接口常用方法 中;
五、HashMap 和 TreeMap 区别