这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战
Map 是 Java 中常用集合之一,其重点实现类包括 HashMap、LinkedHashMap、TreeMap 和 Hashtable。
注意:Map 是集合,但并不属于 Collection。
HashMap
HashMap 的底层采用数组 + 链表 / 红黑树(JDK 1.8)。HashMap 键的唯一性,是通过 hashcode 来保证的,因此,若其键为实体,则需要重写 equals() 和 hashcode()。
LinkedHashMap
LinkedHashMap 是 HashMap 的一种特殊形式,其 Entry 加入了 before 和 after,从而使其底层变为了数组 + 双向链表的形式。双向链表记录了整个 table 的顺序,因此 LinkedHashMap 是有序的。
static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
HashMap 和 LinkedHashMap 的结构示意图如下:
Hashtable
Hashtable 是线程安全的,但因为性能问题,已被废弃。在多线程环境中,可以使用 Collections.synchronizedMap 或者 ConcurrentHashMap,前者加锁的地方更多,因此后者的性能更好。
其它 Map
- IdentityHashMap 允许键值为 null,不能保证插入遍历的顺序一致。其特殊的地方是用 == 来比较 key 是否相等,而不是 equals。
- WeakHashMap 的 key 报错了实际对象的弱引用,因此键值对会随着实际对象的回收而自动删除,不太常用。
- TreeM 是非线程安全的,基于红黑树实现,因为该树总处于平衡状态,因此没有调优选项。不过可以通过重写比较器来实现自定义排序。
总结
| key | value | 容量 | 扩容 | 有序性 | 父类 | hashcode | 说明 | |
|---|---|---|---|---|---|---|---|---|
| HashMap | 允许 null | 允许 null | 16 | 2n | 无序 | AbstractMap | 重新计算 | 非线程安全 |
| LinkedHashMap | 允许 null | 允许 null | 16 | 2n | 有序 | AbstractMap | 重新计算 | 非线程安全 |
| TreeMap | 不允许 null | 允许 null | 16 | 2n | 自然排序 | AbstractMap | 重新计算 | 非线程安全 |
| ConcurrentHashMap | 不允许 null | 不允许 null | 16 | 2n | 无序 | AbstractMap | 重新计算 | 锁分段技术 |
| Hashtable | 不允许 null | 不允许 null | 11 | 2n+1 | 无序 | Dictionary | 直接使用 | 线程安全 |