是否可以使用 java 的 hashcode 函数为不同的字符串使用相同的 hashcode?或者如果有可能,那么它的可能性是多少?
12 回答
Java 哈希码是 32 位。它散列的可能字符串的数量是无限的。
所以是的,会有碰撞。百分比是没有意义的——有无限数量的项目(字符串)和有限数量的可能散列。
是的。很多。
看看下面的一对
- “FB”和“Ea”
即使其中的字符不同,也可以返回相同的哈希码。
基本上它是字符串中字符的总和乘以一个整数。
如果有可能,那么其可能性的百分比是多少?
这不是一个特别有意义的问题。
但是,除非String::hashcode
函数或生成对象的方式存在系统性偏差,否则String
任何两个不同(不相等)String
对象具有相同哈希码的概率将为 2 32中的 1 。
这假设字符串是从所有可能的字符串值的集合中随机选择的。如果您以各种方式限制集合,则概率将与上述数字不同。(例如,“FB”/“Ea”冲突的存在意味着所有 2 个字母字符串的集合中发生冲突的概率高于规范。)
另一件需要注意的事情是,随机选择 2 32 个不同的字符串(来自更大的无偏字符串集)没有哈希冲突的机会非常小。要了解原因,请阅读关于生日悖论的维基百科页面。
实际上,在一组 2 32 个不同的字符串中没有哈希冲突的唯一方法是选择或生成字符串。即使通过选择随机生成的字符串来形成集合,计算量也会很大。为了有效地生成这样的集合,您需要利用String::hashCode
算法的属性,(幸运的是)已指定。
是的,这是完全可能的。字符串(或其他对象类型——假设您将在本例中使用字符串)与集合中的其他字符串具有相同哈希码的概率取决于该集合的大小(假设所有字符串在该系列是独一无二的)。概率分布如下:
- 对于一组大小约为 9,000 的集合,您将有 1% 的机会使两个字符串与集合中的哈希发生冲突
- 对于大小约为 30,000 的集合,您将有 10% 的机会使两个字符串与集合中的哈希发生冲突
- 对于一组大小约为 77,000 的集合,您将有 50% 的机会使两个字符串与集合中的哈希发生冲突
所做的假设是:
- hashCode 函数没有偏差
- 上述集合中的每个字符串都是唯一的
这个网站解释得很清楚:http ://eclipsesource.com/blogs/2012/09/04/the-3-things-you-should-know-about-hashcode/ (看“你应该知道的第二件事”)
这不会直接回答您的问题,但我希望它有所帮助。
以下来自java.lang.String
.
/**
* Returns a hash code for this string. The hash code for a
* <code>String</code> object is computed as
* <blockquote><pre>
* s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
* </pre></blockquote>
* using <code>int</code> arithmetic, where <code>s[i]</code> is the
* <i>i</i>th character of the string, <code>n</code> is the length of
* the string, and <code>^</code> indicates exponentiation.
* (The hash value of the empty string is zero.)
*
* @return a hash code value for this object.
*/
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
是的,两个字符串可能具有相同的哈希码 - 如果您查看Wikipedia 文章,您会看到两者都"FB"
具有"Ea"
相同的哈希码。方法契约中没有任何内容说 ahashCode()
应该用于比较相等性,您想使用equals()
它。
从 Java 1.2 开始,StringhashCode()
通过对字符串的整个文本使用积和算法来实现。
是的,根据鸽子洞概念的定义,两个不同的字符串可以产生相同的哈希码,并且应该始终编写代码以适应这种情况(通常是不中断。)
随机字符串的冲突百分比应该是最小的。但是,如果您从外部来源散列字符串,攻击者可以轻松创建数十万个具有相同散列码的字符串。在 java HashMap 中,这些都将映射到同一个存储桶并有效地将映射转换为链表。然后,对地图的访问时间将与地图大小成正比,而不是常数,从而导致拒绝服务攻击。
请参阅此页面关于针对 Web 应用程序平台的有效 DoS 攻击,以获取指向演示文稿的更多信息链接。
是的,这是可能的,因为 Object 类的 equals() 和 hashCode() 方法之间的约定之一是………… 如果两个对象根据 equals() 方法不相等,则没有保证他们的 hashCode 将相同,hashCode 可能/可能不相等。即,如果 obj1.equals(obj2) 返回 false,则 obj1.hashCode()==obj2.hashCode() 可能/可能不会返回 true。 例子:
String str1 = "FB";
String str2 = "Ea";
System.out.println(str1.equals(str2));// false
System.out.println(str1.hashCode() == str2.hashCode()); // true
//你可以用-Xmx2100m运行下面的代码,可以得到多个结果,足以填满你的控制台
`
import java.util.HashMap;
public class TestHashCollision {
public static void main(String[] args) {
final String TEXT = "was stored earlier had the same hash as";
HashMap<Integer,String> hs=new HashMap<>();
long t1=System.currentTimeMillis();
long t2=System.currentTimeMillis();
for(long l=0;l<Long.MAX_VALUE;l++) {
String key="d"+l;
if(hs.containsKey(key.hashCode())) {
System.out.println("'"+hs.get(key.hashCode())+"' "+TEXT+" '"+key+"'");//System.exit(0);
} else {
hs.put(key.hashCode(),key);
}
t2=System.currentTimeMillis();
if(t2-t1>10000) {
t1=System.currentTimeMillis();
System.out.println("10 seconds gone! size is:"+hs.size());
}
}
System.out.println("Done");
}
}
`
"tensada".hashCode()
"friabili".hashCode());
java 哈希函数在这里返回相等的值。