既然 Java 在使用 New 关键字时会创建一个新对象,并且每个对象都有唯一的哈希码,那么为什么它在这里给出相同的哈希码输出呢?

since java creates a new object when new keyword is used, and every object has unique hashcode, then why here it is giving same hashcode output?

提问人:Shrey Saxena 提问时间:9/23/2023 最后编辑:M. JustinShrey Saxena 更新时间:9/23/2023 访问量:65

问:

public class Main {

    public static void main(String[] args) {
        String str1="shrey";
        String str2="shrey";
        String str3=new String("shrey");
        System.out.println(str1.hashCode());
        System.out.println(str2.hashCode());
        System.out.println(str3.hashCode());
    }
}

输出 = 所有 str1、str2、str3 的相同哈希码

Java 使用字符串池。我知道。 并且是使用字符串文字创建的,因此它们应该引用相同的对象,因此将生成相同的哈希码,但是,是使用关键字创建的,所以我期望哈希码是不同的,但结果是相同的。为什么?str1str2str3newstr3

Java 字符串 对象 哈希码

评论

8赞 Thiyagu 9/23/2023
*[...] every object has unique hashcode*- 那不是真的。不可能将无限数量的可能对象映射到一组有限的哈希码。此外,相等的对象应该具有相同的哈希码。在这里,字符串的哈希码基于单个字符。
4赞 Stephen C 9/23/2023
在方法的规范中,没有一处说哈希码是唯一的。Object::hashCode
3赞 MadProgrammer 9/23/2023
hashCode与任何两个对象的关系也应该相同 - 快速谷歌了解更多详情equalsequalhashCode

答:

3赞 Stephen C 9/23/2023 #1

您的问题基于错误的假设:

由于 java 在使用 new 关键字时会创建一个新对象,

正确

...每个对象都有唯一的哈希码,

不對!任何 Java 规范中都没有规定哈希码是唯一的。事实上,最接近这一点的是 javadocs 中的这一行。Object

“实现要求:在合理可行的范围内,由 Object 类定义的 hashCode 方法为不同的对象返回不同的整数。”

也就是说,如果可以的话,试着让它们与众不同......但这并不能保证它们会有所不同。事实上,在 Java 的上下文中,要保证这一点是不可能的。

...那为什么它在这里给出相同的哈希码输出呢?

这与.您的代码实际上是在调用 ,并且指定它返回一个独立于字符串标识的值。javadoc 指出:Object::hashCodeString::hashCodeString

“返回此字符串的哈希代码。String 对象的哈希代码计算为

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

使用 int 算术,其中 s[i] 是字符串的第 i个字符,n 是字符串的长度,^ 表示幂。

您的字符串都具有相同的长度和相同的字符,这意味着将给出相同的结果。String::hashCode

我们还可以从 javadocs 的属性中推断出情况应该如此。简明扼要地说:hashCodeequalsObject

s1.equals(s2) == true  implies  s1.hashCode() == s2.hashCode()
0赞 user22618554 9/23/2023 #2

Java 编程语言和契约规定,根据方法,两个相等的对象必须具有相等的哈希码,而具有相等哈希码的两个对象可能因人而异。equalshashCodeequals(Object object)

在您喜欢的 Java 编程语言版本的类的 Java 文档中,有关于方法协定的详细信息。hashCodeObject

1赞 M. Justin 9/23/2023 #3

您断言“每个对象都有一个唯一的哈希码”是不正确的。相反,规则是相等的对象必须具有相同的哈希代码。不相等的对象可能具有也可能没有不同的哈希码(尽管出于性能原因,大多数不相等的对象都具有不同的哈希码)。

根据 hashCode 的合约,相等的对象必须具有相等的哈希码:

如果根据 equals 方法,两个对象相等,则对两个对象中的每一个调用该方法必须产生相同的整数结果。hashCode

根据 Javadocs,当两个值表示相同的字符序列时,它们被认为是相等的:StringStringequals

当且仅当参数不为 null 并且是一个 String 对象,该对象表示与此对象相同的字符序列时,结果为 true。

"shrey"并表示相同的字符序列(即 )。因此,它们根据并且必须具有相同的哈希码是相等的。new String("shrey"){'s', 'h', 'r', 'e', 'y'}equals

最后,为了添加更多的上下文,Javadocs 解释了两个不相等的对象可能具有相同的哈希代码,尽管这样做会带来性能后果:hashCode

如果根据 equals 方法,如果两个对象不相等,则不需要对两个对象中的每一个调用 hashCode 方法必须产生不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

0赞 Christian Meyer 9/23/2023 #4

#hashcode将为所有对象提供相同的哈希值,这些对象的字面值相同。因此,任何值为“eclips3”的字符串,无论它如何构造,也无论是否应用,都将具有相同的哈希码。#intern

更适合你的目的的是 ,它基本上是 by Object 在被覆盖之前的原始实现。因此,我们可以使用此方法来区分引用 [存储在单独的内存位置],即使它们具有相同的文本值。System.identityHashCode(stringObj)#hashcode

这里有一个基本的演示,可以帮助你得到一个更好的想法。

        String s1 = "eclips3";
        String s2 = new String("eclips3");
        String s3 = new String("eclips3");
        String s4 = s2.intern();
        String s5 = new String("eclips3").intern();

        System.out.println(System.identityHashCode(s1));
        System.out.println(System.identityHashCode(s2));
        System.out.println(System.identityHashCode(s3));
        System.out.println(System.identityHashCode(s4));
        System.out.println(System.identityHashCode(s5));
        
        System.out.println("s1 == s2? " + String.valueOf(s1==s2));
        System.out.println("s1 == s3? " + String.valueOf(s1==s3));
        System.out.println("s1 == s4? " + String.valueOf(s1==s4));
        System.out.println("s1 == s5? " + String.valueOf(s1==s5));
        System.out.println("s2 == s3? " + String.valueOf(s2==s3));
        System.out.println("s2 == s4? " + String.valueOf(s2==s4));
        System.out.println("s2 == s5? " + String.valueOf(s2==s5));
        System.out.println("s3 == s4? " + String.valueOf(s3==s4));
        System.out.println("s3 == s5? " + String.valueOf(s3==s5));
        System.out.println("s4 == s5? " + String.valueOf(s4==s5));

我的系统上的结果:

95980430
1478835287
12006451
95980430
95980430
s1 == s2? false
s1 == s3? false
s1 == s4? true
s1 == s5? true
s2 == s3? false
s2 == s4? false
s2 == s5? false
s3 == s4? false
s3 == s5? false
s4 == s5? true