Java的hashCode可以为不同的字符串生成相同的值吗?

时间:2012-04-11 08:22:01

标签: java hashcode

是否可以使用java的哈希码函数为不同的字符串使用相同的哈希码?或者如果可能的话,它的可能性百分比是多少?

12 个答案:

答案 0 :(得分:58)

Java哈希码是32位。它散列的可能字符串数量是无限的。

是的,会有碰撞。百分比毫无意义 - 存在无限数量的项(字符串)和有限数量的可能哈希值。

答案 1 :(得分:22)

YES。很多。

看下面的一对

  • “FB”和“Ea”

可以返回相同的哈希码,即使其中的字符不相同。

基本上它是字符串中字符的总和乘以整数。

答案 2 :(得分:8)

  

如果有可能那么它的可能性百分比是多少?

这不是一个特别有意义的问题。

但是,除非String::hashcode函数或生成String对象的方式存在某些系统偏差,否则任何两个不同(不相等)String的概率对象将具有相同的哈希码,将为1 in 2 32

这假定从所有可能的String值集合中随机选择字符串。如果以各种方式限制集合,则概率将与上述数字不同。 (例如,“FB”/“Ea”碰撞的存在意味着所有2个字母串的集合中的碰撞概率高于标准。)


另外需要注意的是,没有哈希冲突的随机选择的2 32 不同字符串的机会是消失小。要了解原因,请阅读Birthday Paradox上的维基百科页面。

实际上,如果您选择或生成字符串,唯一的方法就是在一组2个 32 不同字符串中获得无哈希冲突。即使通过选择随机生成的字符串来形成集合也将是计算上昂贵的。要有效地生成这样的集合,您需要利用String::hashCode算法的属性(幸运的是)。

答案 3 :(得分:8)

是的,完全有可能。字符串(或其他一些对象类型 - 假设您将使用此示例中的字符串)与集合中的其他字符串具有相同哈希码的概率取决于该集合的大小(假设所有该集合中的字符串是唯一的)。概率分布如下:

  • 使用一组大小~9,000,你有2%的几率与两个字符串碰撞集合
  • 使用一组大小~30,000,你有10%的几率使两个字符串与集合中的哈希冲突
  • 使用一组大小~77,000,你有50%的几率使两个字符串与集合中的哈希冲突

所做的假设是:

  • hashCode函数没有偏见
  • 上述集合中的每个字符串都是唯一的

此网站清楚地解释了这一点:http://eclipsesource.com/blogs/2012/09/04/the-3-things-you-should-know-about-hashcode/ (看看"你应该知道的第二件事")

答案 4 :(得分:6)

这不会直接回答你的问题,但我希望它有所帮助。

以下内容来自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;
}

答案 5 :(得分:5)

是的,两个字符串可能具有相同的哈希码 - 如果您查看Wikipedia article,您会发现"FB""Ea"具有相同的哈希码。方法合同中没有任何内容表示应使用hashCode()来比较相等性,您希望使用equals()

自Java 1.2起,String通过using a product sum algorithm over the entire text of the string实现hashCode()

答案 6 :(得分:4)

是的,根据鸽子洞概念的定义,两个不同的字符串可以产生相同的哈希码,并且应该始终编写代码以满足这些条件(通常不会破坏。)

答案 7 :(得分:2)

随机字符串的冲突百分比应该是最小的。但是,如果您从外部源散列字符串,攻击者可以轻松创建数十万个具有相同哈希码的字符串。在Java HashMap中,这些都将映射到同一个存储桶,并有效地将地图转换为链接列表。然后,地图的访问时间将与地图大小成比例而不是常数,从而导致拒绝服务攻击。

有关演示文稿的更多信息,请参阅Effective DoS attacks against Web Application Plattforms上的此页面。

答案 8 :(得分:2)

是的,这是可能的,因为equals()&amp;之间的合同之一。 Object类的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

答案 9 :(得分:0)

//您可以使用-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"); 
    }
}

`

答案 10 :(得分:0)

是的(不仅仅是Java,它适用于任何语言),它可以为不同的字符串生成相同的哈希码。 我想起了我教授教授的一条规则,在这里可能有用-

  

两个相同的字符串/值必须具有相同的哈希码,但反之则不成立。

python中的示例

>>> hash('same-string')
-5833666992484370527
>>> hash('same-string')
-5833666992484370527

可能还有另一个字符串可以匹配相同的哈希码,因此我们不能使用哈希码来导出密钥。

  

两个不同的字符串具有相同的哈希码的原因是由于冲突。   enter image description here

答案 11 :(得分:-2)

nativeQuery = true

java哈希函数在此处返回相等的值。

相关问题