23

是否有任何理由无法使用它的 hashCode 方法测试 Java 字符串的相等性?所以基本上,而不是......

"hello".equals("hello")

你可以用...

"hello".hashCode() == "hello".hashCode()

这将很有用,因为一旦一个字符串计算出它的哈希码,那么比较一个字符串将与比较一个 int 一样有效,因为字符串缓存了哈希码,而且很可能无论如何该字符串都在字符串池中,如果你设计它方式。

4

9 回答 9

39

因为:如果对象相等,两个对象的hashCodes必须相等,但是,如果两个对象不相等,hashCode仍然可以相等。

(评论后修改)

于 2009-09-23T12:17:57.390 回答
39

让我给你一个反例。试试这个,

public static void main(String[] args) {
    String str1 = "0-42L";
    String str2 = "0-43-";

    System.out.println("String equality: " + str1.equals(str2));
    System.out.println("HashCode eqauality: " + (str1.hashCode() == str2.hashCode()));
}

我的Java上的结果,

String equality: false
HashCode eqauality: true
于 2009-09-23T12:38:24.960 回答
16

正如许多人所说,hashCode 不保证唯一性。事实上,它不能这样做,原因很简单。

hashCode 返回一个 int,这意味着有 2^32 个可能的值(大约 4,000,000,000),但肯定有超过 2^32 个可能的字符串,这意味着至少两个字符串具有相同的 hashcode 值。

这就是所谓的鸽洞原理

于 2009-09-23T12:50:13.927 回答
8

其他人指出了为什么它不起作用。因此,我将添加补充说明,无论如何增益都会很小。

在 Java 中比较两个字符串时,String equals 函数首先检查它们是否是对同一对象的两个引用。如果是这样,它立即返回 true。然后它检查长度是否相等。如果不是,则返回 false。只有这样它才会开始逐个字符进行比较。

如果您正在处理内存中的数据,相同对象的比较可能会很快处理“相同”的情况,我认为这是一个快速的、嗯、4 字节的整数比较。(如果我的对象句柄长度错误,请有人纠正我。)

对于大多数不相等的字符串,我敢打赌,长度比较很快就会发现它们不相等。如果您要比较事物的两个名称——客户、城市、产品等等——它们的长度通常不相等。因此,一个简单的 int 比较可以快速处理它们。

性能最差的情况是两个长的、相同但不相同的对象字符串。然后它必须做对象句柄比较,假的,继续检查。长度比较,真实,继续检查。然后逐个字符地遍历字符串的整个长度,以验证它们确实是相等的,直到最后。

于 2009-09-23T13:10:08.800 回答
4

您可以获得您想要使用的效果String.intern()(使用哈希表实现。)

您可以比较intern()使用==运算符的返回值。如果它们引用相同的字符串,那么原始字符串是等价的(即equals()会返回true),并且只需要一个指针比较(与比较具有相同的成本int)。

String a = "Hello";
String b = "Hel" + "lo";

System.out.println(a.equals(b));
System.out.println(a == b);

String a2 = a.intern();
String b2 = b.intern();

System.out.println(a2.equals(b2));
System.out.println(a2 == b2);

输出:

true
false
true
true
于 2009-09-23T12:46:58.753 回答
1

hashCode 值不是唯一的,这意味着字符串可能实际上并不匹配。为了提高性能,equals 的实现通常会在执行更费力的检查之前执行 hashCode 检查。

于 2009-09-23T12:18:29.543 回答
1

非常简单的原因:冲突的风险......哈希码的可能值比字符串少得多。这取决于您生成的散列类型,但让我们举一个非常简单的示例,您将添加字母的序数值,乘以它的位置:a=1、b=2 等。因此,“你好”会转换为:h:8x1=8,e:5x2=10,l:12x3=36,l:12x4=48,o:15x5=75。8+10+36+48+75=177。

是否有其他字符串值可以以 177 散列结尾?当然!有很多选择。随意计算一些。

尽管如此,这种散列方法还是使用了一种简单的方法。Java 和 .NET 使用更复杂的散列算法,这种冲突的可能性要小得多。但是,仍然有可能两个不同的字符串会产生相同的哈希值,因此这种方法不太可靠。

于 2009-09-23T12:23:09.797 回答
0

两个不同的 String 可以很容易地生成相同的 hash Code 或不同的 hash Code。如果你想要一个相等测试哈希代码不会给出一个唯一的结果。当我们使用 String 类时,它会返回不同的哈希码值。所以字符串缓冲区类应该适用于每个连接对象具有相同的哈希码。

于 2017-08-29T12:36:37.243 回答
-2

正如您所描述的,没有理由不使用 hashCode 。

但是,您必须注意碰撞。有一个机会 - 诚然是一个小机会 - 两个不同的字符串确实散列到相同的值。考虑首先做一个 hashCode,如果相等也使用 equals() 做完整的比较。

于 2009-09-23T12:19:26.750 回答