Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么认为这个hashCode()方法很差?_Java_Performance_Hashmap_Hashcode - Fatal编程技术网

Java 为什么认为这个hashCode()方法很差?

Java 为什么认为这个hashCode()方法很差?,java,performance,hashmap,hashcode,Java,Performance,Hashmap,Hashcode,这是对“”的后续问题。有许多有趣的评论。有些我很了解;其他人则更少 为什么这个hashCode()方法被认为很差 乍一看,我认为这是合理的。也许17个可以增加到31个。否则,它似乎遵循Arrays.hashCode(Object[])中普遍接受的公式。一个猜测:它适用于项目数量相对较少(小于10.000)的一般情况,但对于非常大的集合(1.000.000或更多)性能较差 以下是原始代码:(包含所有代码是为了提供一些上下文。) import java.util.HashMap; 导入java.ut

这是对“”的后续问题。有许多有趣的评论。有些我很了解;其他人则更少

为什么这个
hashCode()
方法被认为很差

乍一看,我认为这是合理的。也许17个可以增加到31个。否则,它似乎遵循
Arrays.hashCode(Object[])
中普遍接受的公式。一个猜测:它适用于项目数量相对较少(小于10.000)的一般情况,但对于非常大的集合(1.000.000或更多)性能较差

以下是原始代码:(包含所有代码是为了提供一些上下文。)

import java.util.HashMap;
导入java.util.Map;
导入java.util.Random;
公共类Test1{
静态int max_k1=500;
静态int max_k2=500;
静态地图;
静态随机=新随机();
公共静态void main(字符串[]args){
对于(int i=0;i<15;i++){
长启动=System.nanoTime();
run();
long end=System.nanoTime();
系统输出打印项次((结束-开始)/1000_000);
}
}
私有静态无效运行(){
map=新的HashMap();
对于(int i=0;i<10_000;i++){
节点键=新节点(random.nextInt(max_k1)、random.nextInt(max_k2));
节点val=getOrElseUpdate(键);
}
}
私有静态节点GetOrelsUpdate(节点密钥){
节点val;
if((val=map.get(key))==null){
val=键;
地图放置(键,val);
}
返回val;
}
私有静态类节点{
私人int k1;
私人int k2;
公共节点(int k1,int k2){
这是1.k1=k1;
这是1.k2=k2;
}
@凌驾
公共int hashCode(){
int结果=17;
结果=31*结果+k1;
结果=31*结果+k2;
返回结果;
}
@凌驾
公共布尔等于(对象obj){
if(this==obj)
返回true;
如果(!(节点的obj实例))
返回false;
节点其他=(节点)obj;
返回k1==other.k1&&k2==other.k2;
}
}
}

坦率地说,问题在于,当输入范围很小时,它不能很好地工作。当您有字符串之类的东西时,它可以正常工作,但不适用于小整数

你可以考虑使用杂凑算法,比如咕哝。如果您可以使用像Guava这样的第三方库,这可能是

return Hashing.murmur3_32().newHasher().putInt(k1).putInt(k2).hash().asInt();

问题是,坦白说,当输入范围很小时,它不能很好地工作。当您有字符串之类的东西时,它可以正常工作,但不适用于小整数

你可以考虑使用杂凑算法,比如咕哝。如果您可以使用像Guava这样的第三方库,这可能是

return Hashing.murmur3_32().newHasher().putInt(k1).putInt(k2).hash().asInt();

您的散列函数可以写为31*17*31+31*k1+k2

您可以看到,将31添加到k2,将-1添加到k1将产生相同的散列值

那么大约在1到500之间的每一对数字都会有一打左右 (500/31)具有相同散列的其他对

在示例代码中完美执行的哈希函数是500*k1+k2。 (快速测试显示性能提高约3倍。)

正如Louis Wasserman所指出的,使用了一位经过充分研究的将军 库中的哈希函数可能是一个安全的赌注

至于为什么标准数组散列函数在这种情况下表现不佳(顺便说一句,IntelliJ默认生成相同的函数)

这里不要求进行完整的分析,但显然散列变量的数量越大(假设它们在某种意义上是独立的),并且每个变量的可能值集越大,函数的性能就越好。在您的例子中,性能很差,因为只有两个变量,而且它们的范围都很小

在Java8中,HashMap实现似乎变得更加复杂,可能是为了在某些场景中获得更好的渐近性能而进行了优化。这种微小的增加的复杂性加上性能不佳的哈希函数,导致性能下降


在这方面,这可能是一个更好的算法。作为一种更简单的结构和更少的缓存未命中,它应该能够在读取繁重的工作负载中提供更好的性能。我对提供良好的通用线性探测哈希映射的Java库很感兴趣。

您的哈希函数可以写成31*17*31+31*k1+k2

您可以看到,将31添加到k2,将-1添加到k1将产生相同的散列值

那么大约在1到500之间的每一对数字都会有一打左右 (500/31)具有相同散列的其他对

在示例代码中完美执行的哈希函数是500*k1+k2。 (快速测试显示性能提高约3倍。)

正如Louis Wasserman所指出的,使用了一位经过充分研究的将军 库中的哈希函数可能是一个安全的赌注

至于为什么标准数组散列函数在这种情况下表现不佳(顺便说一句,IntelliJ默认生成相同的函数)

这里不要求进行完整的分析,但显然散列变量的数量越大(假设它们在某种意义上是独立的),并且每个变量的可能值集越大,函数的性能就越好。在您的例子中,性能很差,因为只有两个变量,而且它们的范围都很小

在Java8中,HashMap实现似乎变得更加复杂,可能是为了在某些场景中获得更好的渐近性能而进行了优化。这种微小的增加的复杂性加上性能不佳的哈希函数,导致性能下降


在这方面,这可能是一个更好的算法。作为一种更简单的结构和更少的缓存未命中,它应该能够在读取繁重的工作负载中提供更好的性能。我对一个Java库很感兴趣,它提供了良好的通用线性探测哈希映射。

我是告诉你它很差的人之一。我给了你理由:“250000个可能的
节点
值,它只有15969个散列码。”

如果您的
节点
项应该是