Java 哈希表中的哈希函数与哈希映射?
我知道Hashtable和HashMap之间的区别。然而,这两个类似乎都在使用散列函数来完成任务。Hashtable中使用的哈希函数与HashMap中使用的哈希函数之间是否存在差异 特别是,他们使用的散列算法之间有什么区别吗?这两个类中用于散列的公式是什么 换句话说,计算索引(散列值)的方法不同吗?Java 哈希表中的哈希函数与哈希映射?,java,algorithm,hash,hashmap,hashtable,Java,Algorithm,Hash,Hashmap,Hashtable,我知道Hashtable和HashMap之间的区别。然而,这两个类似乎都在使用散列函数来完成任务。Hashtable中使用的哈希函数与HashMap中使用的哈希函数之间是否存在差异 特别是,他们使用的散列算法之间有什么区别吗?这两个类中用于散列的公式是什么 换句话说,计算索引(散列值)的方法不同吗?java.util.Hashtable类似于java.util.Vector。它是在开发早期添加到SDK中的一个类,已被HashMap取代(如ArrayList取代Vector) 因此,除非需要隐式同
java.util.Hashtable
类似于java.util.Vector
。它是在开发早期添加到SDK中的一个类,已被HashMap
取代(如ArrayList
取代Vector
)
因此,除非需要隐式同步所有操作(默认情况下是Hashtable
),否则不应该使用它,但您仍然可以使用集合。synchronizedMap
或ConcurrentHashMap
如Javadoc中所述:
从Java2平台v1.2开始,该类经过了改造,实现了Map
接口,使其成为Java集合框架的成员。与新的集合实现不同,哈希表
是同步的。如果不需要线程安全实现,建议使用HashMap
代替Hashtable
。如果需要线程安全的高并发实现,则建议使用ConcurrentHashMap
代替Hashtable
这两个类的散列应该相同,因为它们都将使用int Object::hashCode
特别是,他们使用的散列算法之间有什么区别吗?这两个类中用于散列的公式是什么
将对象用作哈希表键时使用的主要哈希函数是对象的hashCode()
方法。由key类来实现一个合适的散列函数
Hashtable
和HashMap
类获取键的hashcode值,并将其转换为链的主Hashtable数组中的索引。但是,在Hashtable
和HashMap
之间发生这种情况的方式有所不同
- 对于哈希表(Java 8),代码如下:
hash = key.hashCode(); index = (hash & 0x7FFFFFFF) % tab.length;
- 对于
(Java 8),代码(实际上)如下:HashMap
HashMap
正在对键的hashcode函数返回的hashcode值进行置乱。这在源代码中解释如下:
[此方法]计算key.hashCode()并将散列的高位(XOR)扩展到低位。由于该表使用两个掩码的幂,因此仅在当前掩码上方的位上变化的哈希集将始终冲突。(已知的例子中有一组在小表格中保存连续整数的浮点键。)因此,我们应用了一种向下传播高位影响的变换。在比特传播的速度、效用和质量之间存在一种折衷。由于许多常见的散列集已经合理分布(因此无法从传播中获益),并且由于我们使用树来处理容器中的大型冲突集,因此我们只需以最便宜的方式对一些移位位进行异或,以减少系统损失,以及合并最高位的影响,否则,由于表边界,最高位将永远不会用于索引计算
注:
&
与%
的区别在于,在哈希表中,哈希数组大小是一个素数,而在哈希映射(Java8)中,哈希数组大小是2的幂
HashMap
中,如果键类实现了Comparable
,那么实现将把一个长的哈希链变成一个二叉树HashMap
处理null
键,但Hashtable
不处理然而,
HashMap
中所有这些额外的复杂性只有在密钥类的hashCode()
方法设计/实现不好时才会发挥作用。。。或者如果有人故意试图设计散列冲突
换句话说,如果您的键类设计得很好,那么差异应该无关紧要。可能的重复在最后,两者都使用添加到集合中的对象的
hashCode()
。因此,确定“hash”的算法取决于如何在添加的对象上实现hashCode()
。(或者它通常是如何在对象上实现的)实际上,对于Java8来说,算法(明显)不同;看看我的答案。@Tibrogargan我不认为这是那个问题的重复。至少我在这里看不到我的答案。例如,在ArrayList中,当容量达到时,数组的大小乘以1.5;然而,在向量中,这个比率是2。因此,它们并不完全相同。这并不重要。@A.Mashreghi这是一个实现细节,为什么它会让你担心?实际上,对于Java 8来说,算法(明显)不同;请参阅我的答案。@A.Mashreghi-可以说,这与散列算法没有区别。相反,这是调整大小算法的不同之处。
// (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;