请解释 Java 中 Hashtable、HashMap 与 TreeMap 各自的特点,并说明它们在线程安全性、顺序性、键值对是否允许 null、底层实现及适用场景等方面的主要区别。
考察说明
考查对 Java 常用 Map 实现类的理解程度,以及能否从线程安全、顺序、null 支持等角度进行对比。
回答思路
- 【回答框架 1】Hashtable 是早期线程安全的 Map 实现,其方法使用 synchronized 修饰,因此同一时刻只有一个线程能进行读写,但并发度低,性能较差。它不允许 null 键和 null 值,否则抛出 NullPointerException。底层基于哈希表,存储无序。
- 【回答框架 2】HashMap 是非线程安全的 Map 实现,允许一个 null 键和多个 null 值,底层采用数组加链表加红黑树的结构(JDK 8 后),当链表长度超过阈值且数组容量达标时树化以提高查询效率。它不保证迭代顺序,如果需要线程安全可使用 ConcurrentHashMap。
- 【回答框架 3】TreeMap 基于红黑树实现,按键的自然顺序或构造时传入的 Comparator 进行排序,因此是有序的,但不允许 null 键(自然顺序下),允许 null 值。其查找、插入和删除的时间复杂度为 O(log n),适用于需要排序或范围查找的场景。
- 【回答框架 4】三者选择依据:线程安全且兼容旧代码可选 Hashtable,但现代并发环境应使用 ConcurrentHashMap;无需排序则默认使用 HashMap;需要按键排序或范围操作则选择 TreeMap。注意 HashMap 的扩容与哈希冲突处理,以及 TreeMap 的比较器一致性。
- 【关键点 1】Hashtable 线程安全但性能低,不允许 null 键值;HashMap 非线程安全,允许一个 null 键与多个 null 值。
- 【关键点 2】TreeMap 基于红黑树,按键排序,不允许 null 键,复杂度 O(log n)。
- 【关键点 3】HashMap 底层为数组+链表+红黑树,JDK 8 引入树化;Hashtable 无此机制。
- 【关键点 4】并发场景推荐 ConcurrentHashMap 替代 Hashtable。
- 【易错点 1】误以为 Hashtable 的所有方法绝对线程安全,但复合操作仍需额外同步。
- 【易错点 2】忽略 HashMap 树化条件,误以为链表长度达到 8 就一定树化,实际上还需满足数组容量达到 64。
- 【易错点 3】TreeMap 使用自定义 Comparator 时需保证比较器与 equals 一致,否则可能违反 Map 接口约定。