我正在研究Java中的HashMap类。我的理解是哈希表的容量是桶数的2次方(容量16表示四个桶)。当调用put(key,value)时,key.hashCode()输出一个整数,这个新添加的(key,value)对基于key . hashcode()%的桶数放置。但是下面是HashMap.class中的实际实现
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
从上面的代码中,我无法理解如何安装钥匙。将hashCode()值转换为bucket。
该代码不“适合”hashCode到bucket,它“只是”散播哈希代码,使高位更重要。这里是该方法的javadoc。
计算key.hashCode()并将哈希的高位扩展(异或)到低位。因为该表使用2的幂掩码,所以仅在当前掩码之上的位不同的散列集将总是冲突。(已知的例子包括在小表格中保存连续整数的多组浮动键。)所以我们应用了一个向下扩展高位影响的变换。在位扩展的速度、效用和质量之间有一个折衷。因为许多常见的散列集合已经被合理地分布(因此不受益于扩散),并且因为我们使用树来处理箱中的大量冲突集合,所以我们只是以最便宜的可能方式异或一些移位的位来减少系统损失,以及合并最高位的影响,否则由于表的界限,这些最高位将永远不会在索引计算中使用。
对存储桶的实际拟合是在getNode(int,Object)
方法中完成的:
first = tab[(n - 1) & hash]
其中哈希
是哈希(对象)
的结果,n
是哈希表的大小。
这可能会有所帮助。如果我们要添加十个带有从 1 到 10 的浮动键的项目。
Map<Float, String> map = new HashMap<>();
int numOfBuckets = 64; // HashMap will have 64 bins after inserting 10 items
String format = "|%1$-5s|%2$-35s|%3$-25s|%4$-35s|%5$-25s|%6$-25s|\n";
System.out.format(format, "i", "raw binary", "right-shifted 16 bits", "rehashed", "bucket before rehashed",
"bucket after rehashed");
for (int i = 1; i <= 10; i++) {
float key = i;
int rawInt = Float.floatToRawIntBits(key);
String binaryString = Long.toBinaryString(rawInt);
String shifted16BitsString = Long.toBinaryString(rawInt >>> 16);
int rehashed = rawInt ^ rawInt >>> 16;
String rehashedString = Long.toBinaryString(rehashed);
// HashMap calculates bin index with (n - 1) & hash
String bucketBeforeRehashed = Long.toString((numOfBuckets - 1) & Objects.hashCode(key));
String bucketAfterRehashed = Long.toString((numOfBuckets - 1) & rehashed);
System.out.format(format, i, binaryString, shifted16BitsString, rehashedString,
bucketBeforeRehashed, bucketAfterRehashed);
map.put(key, Integer.toString(i));
}
它产生:
|i |raw binary |right-shifted 16 bits |rehashed |bucket before rehashed |bucket after rehashed |
|1 |111111100000000000000000000000 |11111110000000 |111111100000000011111110000000 |0 |0 |
|2 |1000000000000000000000000000000 |100000000000000 |1000000000000000100000000000000 |0 |0 |
|3 |1000000010000000000000000000000 |100000001000000 |1000000010000000100000001000000 |0 |0 |
|4 |1000000100000000000000000000000 |100000010000000 |1000000100000000100000010000000 |0 |0 |
|5 |1000000101000000000000000000000 |100000010100000 |1000000101000000100000010100000 |0 |32 |
|6 |1000000110000000000000000000000 |100000011000000 |1000000110000000100000011000000 |0 |0 |
|7 |1000000111000000000000000000000 |100000011100000 |1000000111000000100000011100000 |0 |32 |
|8 |1000001000000000000000000000000 |100000100000000 |1000001000000000100000100000000 |0 |0 |
|9 |1000001000100000000000000000000 |100000100010000 |1000001000100000100000100010000 |0 |16 |
|10 |1000001001000000000000000000000 |100000100100000 |1000001001000000100000100100000 |0 |32 |
我们可以从输出中发现,键的下位都是 0,这导致所有项目都被分配到同一个箱子。但是在执行右移和异或后,分布会变得更好。我认为这是 HashMap 的 hash() 方法中的源代码注释中描述的情况。
用来计算 MD5、SHA 哈希算法的 Java 类库,支持 "MD5", "SHA", "SHA-1", "SHA-256", "SHA-384", "SHA-512". 要求 jdk 1.5 or higher. 使用: java -jar JavaHash-1.0.jar
问题内容: 谁能详细解释这种方法,谢谢。 问题答案: 设计通用哈希码的问题之一是,您将所有这些工作都放在了确保良好的位扩展上,然后有人来使用并以完全撤消的方式使用它。 让我们以一个带有X和Y(均为整数)的坐标类的经典示例为例。 这是一个经典的示例,因为人们会用它来证明这不是一个很好的哈希码,因为通常会有多个对象,其中(所有哈希都为0)或X和Y为Y和X的对象其他(将散列相同)和其他情况下,我们最终得
问题内容: 请在Hashset中澄清我的疑问。考虑以下代码, 在主要我有以下代码 现在,如果我将这些对象添加到哈希集中 我得到这个输出 问题1 :为什么equals()函数仅被调用一次以检查obj3和obj4?为什么不检查其余对象? 问题2 :如果答案是因为它们都具有相同的哈希码,则仅将调用equals,那么为什么下面的代码不调用equals 输出是: 即使将两个相同的对象添加到具有相同哈希码的哈
接下來我要教你另外一種讓你傷腦筋的容器型資料結構,因為一旦你學會這種資料結構,你將擁有超酷的能力。這是最有用的容器:Hash。 Ruby 將這種資料類型叫做「Hash」,有的語言裡它的名稱是「dictionaries」。這兩種名字我都會用到,不過這並不重要,重要的是它們和陣列的區別。你看,針對陣列你可以做這樣的事情: 1 2 3 4 5 6 7 8 9 10 11 ruby-1.9.2-p180
问题内容: 我试图为字符串想出一个很好的哈希函数。而且我当时想对字符串中前五个字符的unicode值进行汇总可能是个好主意(假设它有五个,否则在结尾处停止)。那是一个好主意,还是一个坏主意? 我正在用Java进行此操作,但我无法想象这会带来很大的不同。 问题答案: 通常哈希不会做算术,否则和将具有相同的哈希值。 并且你不会将其限制为前n个字符,因为否则和将具有相同的哈希值。 通常,哈希采用值并将其
本文向大家介绍memcache一致性hash的php实现方法,包括了memcache一致性hash的php实现方法的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了memcache一致性hash的php实现方法。分享给大家供大家参考。具体如下: 最近在看一些分布式方面的文章,所以就用php实现一致性hash来练练手,以前一般用的是最原始的hash取模做 分布式,当生产过程中添加或删除一台me