【问题标题】:Hashing function in Hashtable vs. HashMap?Hashtable 与 HashMap 中的散列函数?
【发布时间】:2016-11-12 05:52:54
【问题描述】:

我知道 Hashtable 和 HashMap 的区别。但是,这两个类似乎都在使用 散列函数 来完成工作。 Hashtable中使用的hash函数和HashMap中使用的hash函数有区别吗?

特别是他们使用的哈希算法有区别吗?这两个类中hash的公式是什么?

也就是说,计算索引(哈希值)的方式不同吗?

【问题讨论】:

  • 最后,两者都使用hashCode() 添加到集合中的对象。因此,确定“哈希”的算法取决于您如何在添加的对象上实现hashCode()。 (或者一般来说它是如何在对象上实现的)
  • 实际上,对于 Java 8,算法(显着)不同;看我的回答。
  • @Tibrogargan 我不认为这是该问题的重复。至少我在那里看不到我的答案。

标签: java algorithm hash hashmap hashtable


【解决方案1】:

特别是他们使用的哈希算法有区别吗?这两个类中用来hash的公式是什么?

将对象用作哈希表键时使用的主要哈希函数是对象的hashCode() 方法。实现一个像样的哈希函数取决于关键类。

HashtableHashMap 类获取键的哈希码值并将其转换为主哈希表链数组中的索引。但是,HashtableHashMap 之间的发生方式有所不同。

  • 对于Hashtable (Java 8),代码如下:

     hash = key.hashCode();
     index = (hash & 0x7FFFFFFF) % tab.length;
    
  • 对于HashMap(Java 8),代码(实际上)是这样的:

     // (I have restructured the code for ease of comparison.)
     int h;
     hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
     index = (tab.length - 1) & hash;
    

如您所见,HashMap 正在对键的 hashcode 函数返回的 hashcode 值进行加扰。这在源代码中解释如下:

[此方法] 计算 key.hashCode() 并将哈希的较高位传播(XOR)到较低位。由于该表使用二次幂掩码,因此仅在当前掩码之上位变化的散列集总是会发生冲突。 (已知的例子是在小表中保存连续整数的 Float 键集。)因此,我们应用了一种变换,将高位的影响向下传播。在位扩展的速度、实用性和质量之间存在折衷。因为许多常见的散列集已经合理分布(所以不要从传播中受益),并且因为我们使用树来处理 bin 中的大量冲突,我们只是以最便宜的方式对一些移位的位进行异或,以减少系统损失,以及合并最高位的影响,否则由于表边界,这些最高位将永远不会用于索引计算。

注意事项:

  1. &% 的区别在于,在 Hashtable 中,哈希数组大小是质数,但在 HashMap (Java 8) 中,大小是 2 的幂。

  2. 在 Java 8 HashMap 中,如果键类实现 Comparable,则该实现会将长哈希链转换为二叉树。

  3. HashMap 处理 null 键,但 Hashtable 不处理。


但是,HashMap 中所有这些额外的复杂性只有在您的密钥类具有设计/实现不佳的 hashCode() 方法时才会发挥作用......或者如果有人故意尝试设计哈希冲突。

换句话说,如果您的键类设计得很好,那么差异应该无关紧要

【讨论】:

    【解决方案2】:

    java.util.Hashtable<K,V> 类似于java.util.Vector<T>。它是在开发早期就添加到 SDK 中的一个类,已被 HashMap<K,V> 取代(如 ArrayList<T> 取代 Vector<T>)。

    所以你根本不应该使用它,除非你需要所有操作的隐式同步,默认情况下使用Hashtable,但你仍然可以使用Collections.synchronizedMapConcurrentHashMap<K,V>

    如 Javadoc 中所述:

    从 Java 2 平台 v1.2 开始,该类被改进为实现 Map 接口,使其成为 Java 集合框架的成员。与新的集合实现不同,Hashtable 是同步的。如果不需要线程安全实现,建议使用HashMap 代替Hashtable。如果需要线程安全的高并发实现,建议使用ConcurrentHashMap 代替Hashtable

    这两个类的哈希值应该相同,因为它们都将使用int Object::hashCode 来实现它们的目的。

    【讨论】:

    • 例如在ArrayList中,当达到容量时,数组的大小乘以1.5;但是,在 Vector 中,这个比率是 2。因此,它们并不完全相同。
    • 这并不重要。
    • @A.Mashreghi 这是一个实现细节,你为什么关心它?
    • 实际上,对于 Java 8,算法(显着)不同;看我的回答。
    • @A.Mashreghi - 可以说,这不是散列算法的区别。相反,这是调整大小算法的不同。
    猜你喜欢
    • 2012-05-26
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    • 2020-10-19
    • 2023-03-26
    • 2010-11-15
    相关资源
    最近更新 更多