美文网首页
(Java) 如何找到两个 hashCode 相等的字符串

(Java) 如何找到两个 hashCode 相等的字符串

作者: jyjz2008 | 来源:发表于2019-04-09 21:53 被阅读0次

题目

Java 中,对每个非 null 的字符串都可以调用 hashCode() 方法,hashCode() 方法的返回值是 int 类型的(这个返回值被称为hashCode),所以理论上字符串的 hashCode 最多有 2^32 种取值,既然字符串有无穷多个,那么一定存在 hashCode 相等的字符串,请找到两个这样的字符串。

思路

String 对象的 hashCode 是如何计算的

先看一下 jdk 里面 java.lang.StringhashCode() 的实现。具体如下图

hashCode() in java.lang.String
简单的解释如下
public int hashCode() {
         // 起到缓存的效果, 防止反复计算 hashCode
        int h = hash;
        // 如果 h != 0, 说明已经计算过 hashCode 了, 直接返回缓存值即可
        if (h == 0 && value.length > 0) {
            char val[] = value;

            // 计算的核心步骤是这个 for 循环
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

看了源码后,就知道 StringhashCode 的计算过程了。例如 "ab" 的 hashCode 为

hashCode = 31 * 97 + 98;// 'a' 对应的整数是 97, 'b' 对应的整数是 98

如果字符串 s 的长度为 1, 那么它只包含一个 char, 这个 char 对应的 int 值就是 shashCode
例如 "A", "B", "a", "b" 这四个StringhashCode 分别为 65, 66, 97(97=65+32), 98(98=66+32)
所以对两个长度为 1String 而言,如果它们包含的 char 不同的话,其 hashCode 必然不等。

我们可以从长度为 2String 入手。
如果字符串 s 长度为 2,则它的 hashCode

hashCode = s[0] * 31 + s[1]

如果 s[0]='A',则

hashCode = 97 * 31 + s[1]

如果 s[0]='B',则

hashCode = (97 + 1) * 31 + s[1]
// 也就是
hashCode = 97 * 31 + s[1] + 31

所以可以想到 "Aa" 和 "BB" 刚好满足要求。

"Aa".hashCode() == "BB".hashCode()

用到的程序如下

package com.naive.wow;

public class HashCode {
    public static void main(String[] args) {
        // 两者的 hashCode 都是 2112  
        System.out.println("Aa".hashCode());
        System.out.println("BB".hashCode());
    }
}

简单的推广

假设字符串 s, t 长度都是 2
shashCode 计算如下

s[0] * 31 + s[1]

thashCode 计算如下

t[0] * 31 + t[1]

如果二者的 hashCode 相等,那么就有

s[0] * 31 + s[1] == t[0] * 31 + t[1]

(s[0] - t[0]) * 31 == t[1] - s[1]

有了这样的结论后,就可以前往 https://codepoints.net/ 找到一些汉字来拼凑出满足要求的字符串了。

下图中展示了“三、个、上、下” 这四个汉字对应的 unicode

“三、个、上、下” 这四个汉字对应的 unicode

不难得到“三个”和“上下”这两个 StringhashCode 是相等的

运行结果

用到的程序如下

public class HashCode {
    public static void main(String[] args) {
        // 两者的 hashCode 都是 639297
        System.out.println("三个".hashCode());
        System.out.println("上下".hashCode());
    }
}

相关文章

网友评论

      本文标题:(Java) 如何找到两个 hashCode 相等的字符串

      本文链接:https://www.haomeiwen.com/subject/uxjbiqtx.html