Map的类关系图
HashMap
实现原理
HashMap内部是通过数组+链表的方法进行实现的。数组类型是Node(实现了Entry)。
对元素增加时,先对元素的key进行hash,得到一个哈希值,哈希值根据数组的长度算出数组的下标hashCode%length
。当多个元素得到同一个数组下标时,为了解决冲突,HashMap在数组后面增加了链表,这样相同hashcode的值就在同一个链表里。相同的key值,value会覆盖掉。
当要查找元素时,先计算key的hashCode得到数组的下标,再对链表进行遍历匹配key值,从而得到value值。
随着元素的增加,数组后面的链表是很长的,而对链表的查找效率是很低的,所以这时候就要进行扩容,在进行动态扩容时,HashMap内部数组默认大小是16,加载因子是0.75,即当75%的数组后面的链表有元素时进行2次幂扩容。
下图是哈希表的结构
jdk1.8中,当发生哈希冲撞使得链表长度达到一定值,使用红黑树来替换链表。
具体的细节可参考jdk1.8中的HashMap
特点
是基于Map接口的实现,存储键值对时,它可以接收null的键值,是线程不安全的。
遍历方式
1.得到Entry集合,for-each遍历,大容量时推荐用
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
2.得到key集合,for-each遍历
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key = " + key + ", Value = " + value);
}
3.得到Entry集合的迭代器
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
HashTable
散列表默认初始值11,动态扩容是2n+1,HashTable的方法都加上了synchronized
。与HashMap不同,不支持null键。
实现原理
与HashMap类似,内部也是数组+链表。
特点
线程安全,公共方法使用了synchronized
,但相对与HashMap效率降低了。