美文网首页
(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