一、Map集合类思维导图
Map:使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。
二、HashMap、Hashtable、LinkedHashMap及TreeMap区别简述
- Hashmap:散列表,存储Key-Value值,继承于AbstractMap,实现Map、Cloneable、Serializable接口,非线程安全,无序
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
- Hashtable:散列表,存储Key-Value值,继承于Dictionary,实现了Map、Cloneable、Java.io.Serializable接口,采用synchronized实现线程安全的,无序
public class Hashtable<K,V>
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable
- LinkedHashMap:双向链表,继承于HashMap,非线程安全的,允许key,value为null,有序
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
- TreeMap:红黑树(自平衡二叉查找树),存储Key-Value值,继承于AbstractMap,实现了NavigableMap、Cloneable、Java.io.Serializable接口,非线程安全,有序
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
三、详解及示例说明
- HashMap
1、存储结构:Entry数组+链表+红黑树
上面左侧是Node[] table哈希桶数组,存放Node链表元素,HashMap最多只允许一条Entry的键位null(多了会覆盖),允许多条Entry的值为null。
HashMap采用哈希表存储,在HashMap中采用拉链法解决哈希冲突;拉链法就是数组+链表,每个数组元素都是一个链表,当Key.hashCode()方法得到hashCode值,然后通过哈希算法(高位运算+取模运算)来定位键值的存储位置,如果Key值相同,则产生哈希碰撞,将数据放在对应下标元素的链表上。
为了让HashMap存储高效,要减少hash碰撞,也就是要hash算法计算结果尽量均匀。如果哈希桶数组很大,较差的hash算法也会分布较均匀,Hash值的范围值是-2147483648~2147483647,前后约40亿的映射空间,基本不会出现碰撞,但是哈希桶数组不可能这么大,内存也放不下;如果hash哈希桶数组很小,较好的hash算法也会很产生较多的hahs碰撞。由此可见,好的Hash算法和好的扩容机制是节省时间&空间和减少hash碰撞的重要因素。
简单看下HashMap如何设计Hash算法,HashMap中hash源码如下
JDK1.7
static int hash(int h) {
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
JDK1.8 Hash算法本质:取key的hashCode值、高位运算、取模运算
static final int hash(Object key) {
int h;
// key.hashCode():返回散列值也就是hashcode
// ^ :按位异或
// >>>:无符号右移,忽略符