hashtable和hashmap扩容方面有什么区别?

1 个回答

  • 孔雀
    首先你要快乐,其次都是其次。
    `Hashtable` 和 `HashMap` 在**扩容机制**上的主要区别主要有三个方面:**触发条件、扩容因子、线程安全影响**。 ## 1. 触发扩容的条件 ### HashMap * 默认初始容量:16 * 默认负载因子:0.75 * **触发条件**:`size >= capacity × loadFactor` * 扩容倍数:**容量 × 2**(翻倍) * JDK 8 中,扩容后会用**链表/红黑树迁移**(链表长度超过 8 且容量≥64时会转红黑树)。 ### Hashtable * 默认初始容量:11 * 默认负载因子:0.75 * **触发条件**:`size >= capacity × loadFactor` 时,调用 `rehash()` * 扩容倍数:**容量 × 2 + 1**(奇数) ## 2. 扩容实现上的区别 | 特性 | HashMap | Hashtable | | ---- | -------------------------------- | ------------------------- | | 初始容量 | 16(可指定,非 2 的幂会自动取最近的 2 次幂) | 11(可指定,直接使用) | | 扩容倍数 | ×2 | ×2 + 1 | | 扩容方法 | `resize()`(JDK8 会重新计算哈希或直接分组到新桶) | `rehash()`(重新计算所有元素的索引位置) | | 数据结构 | 数组 + 链表 + 红黑树(JDK8+) | 数组 + 链表 | | 哈希扰动 | 有扰动函数,减少冲突 | 直接使用 `hashCode()` | ## 3. 线程安全对扩容的影响 * **HashMap** * 非线程安全,扩容时没有锁,多线程下可能出现数据丢失或死循环(JDK7 链表迁移时可能形成环)。 * 在多线程场景建议用 `ConcurrentHashMap`。 * **Hashtable** * 所有方法 `synchronized`,扩容时会阻塞所有读写操作,保证线程安全,但并发性能差。 ## 4. 示例代码验证差异 ```java Hashtable<Integer, String> table = new Hashtable<>(3, 0.75f); // 初始容量 3,扩容阈值 3 * 0.75 = 2.25 table.put(1, "a"); table.put(2, "b"); table.put(3, "c"); // 触发扩容到 3*2+1=7 HashMap<Integer, String> map = new HashMap<>(3, 0.75f); // 初始容量会被调整为 4(最近的 2 的幂),阈值 4*0.75=3 map.put(1, "a"); map.put(2, "b"); map.put(3, "c"); // 达到阈值时扩容到 8 ``` ### 总结对比表 | 对比项 | HashMap | Hashtable | | ---- | -------------------- | ---------- | | 初始容量 | 默认 16,非 2 次幂会调成 2 次幂 | 默认 11,直接使用 | | 扩容倍数 | ×2 | ×2 + 1 | | 触发阈值 | 容量 × 负载因子 | 容量 × 负载因子 | | 线程安全 | 否 | 是(方法级同步) | | 数据结构 | 数组 + 链表 + 红黑树 | 数组 + 链表 |
    发布于 2025-08-13 10:13 •IP属地 内蒙古
    举报
    评论
    收藏