快来,我悄悄的给你说几个HashCode的破事。 (2)

简介: 快来,我悄悄的给你说几个HashCode的破事。 (2)

31x+y=31a+b 可以变形为:


31x-31a=b-y。


即,31(x-a)=b-y。


这个时候就清晰很多了,很明显,上面的等式有一个特殊解:


x-a=1,b-y=31。


因为,由上可得:对于任意两个字符串 xy 和 ab,如果它们满足 x-a=1,即第一个字符的 ASCII 码值相差为 1,同时满足 b-y=31,即第二个字符的 ASCII 码值相差为 -31。那么这两个字符的 hashCode 一定相等。


都已经说的这么清楚了,这样的组合对照着 ASCII 码表来找,不是一抓一大把吗?


Aa 和 BB,对不对?


Ab 和 BC,是不是?


Ac 和 BD,有没有?



image.png


好的。现在,我们可以生成两个 HashCode 一样的字符串了。


我们在稍微加深一点点难度。假设我要构建 2 个以上 HashCode 一样的字符串该怎么办?


我们先分析一下。


Aa 和 BB 的 HashCode 是一样的。我们把它两一排列组合,那不还是一样的吗?


比如这样的:AaBB,BBAa。


image.png


再比如我之前《震惊!ConcurrentHashMap里面也有死循环?》这篇文章中出现过的例子,AaAa,BBBB:


你看,神奇的事情就出现了。


我们有了 4 个 hashCode 一样的字符串了。


image.png


有了这 4 个字符串,我们再去和 Aa,BB 进行组合,比如 AaBBAa,BBAaBB......


4*2=8 种组合方式,我们又能得到 8 个 hashCode 一样的字符串了。


image.png


等等,我好像发现了什么规律似的。


如果我们以 Aa,BB 为种子数据,经过多次排列组合,可以得到任意个数的 hashCode 一样的字符串。字符串的长度随着个数增加而增加。


文字我还说不太清楚,直接 show you code 吧,如下:


public class CreateHashCodeSomeUtil {
    /**
     * 种子数据:两个长度为 2 的 hashCode 一样的字符串
     */
    private static String[] SEED = new String[]{"Aa", "BB"};
    /**
     * 生成 2 的 n 次方个 HashCode 一样的字符串的集合
     */
    public static List<String> hashCodeSomeList(int n) {
        List<String> initList = new ArrayList<String>(Arrays.asList(SEED));
        for (int i = 1; i < n; i++) {
            initList = createByList(initList);
        }
        return initList;
    }
    public static List<String> createByList(List<String> list) {
        List<String> result = new ArrayList<String>();
        for (int i = 0; i < SEED.length; ++i) {
            for (String str : list) {
                result.add(SEED[i] + str);
            }
        }
        return result;
    }
}



通过上面的代码,我们就可以生成任意多个 hashCode 一样的字符串了。

就像这样:


image.png


所以,别再问出这样的问题了:


image.png


image.png


有了这些 hashCode 一样的字符串,我们把这些字符串都放到HashMap 中,代码如下:



public class HashMapTest {
    public static void main(String[] args) {
        Map<String, String> hashMap = new HashMap<String, String>();
        hashMap.put("Aa", "Aa");
        hashMap.put("BB", "BB");
        hashMap.put("AaAa", "AaAa");
        hashMap.put("AaBB", "AaBB");
        hashMap.put("BBAa", "BBAa");
        hashMap.put("BBBB", "BBBB");
        hashMap.put("AaAaAa", "AaAaAa");
        hashMap.put("AaAaBB", "AaAaBB");
        hashMap.put("AaBBAa", "AaBBAa");
        hashMap.put("AaBBBB", "AaBBBB");
        hashMap.put("BBAaAa", "BBAaAa");
        hashMap.put("BBAaBB", "BBAaBB");
        hashMap.put("BBBBAa", "BBBBAa");
        hashMap.put("BBBBBB", "BBBBBB");
    }
}



最后这个 HashMap 的长度会经过两次扩容。扩容之后数组长度为 64:



image.png


但是里面只被占用了三个位置,分别是下标为 0,31,32 的地方


image.png


画图如下:


image.png


看到了吧,刺不刺激,长度为 64 的数组,存 14 个数据,只占用了 3 个位置。


这空间利用率,也太低了吧。


所以,这样就算是 hack 了 HashMap。恭喜你,掌握了一项黑客攻击技术:hash 冲突 Dos 。


如果你想了解的更多。可以看看石头哥的这篇文章:《没想到 Hash 冲突还能这么玩,你的服务中招了吗?》


看到上面的图,不知道大家有没有觉得有什么不对劲的地方?


如果没有,那么我再给你提示一下:数组下标为 32 的位置下,挂了一个长度为 8 的链表。


是不是,恍然大悟了。在 JDK 8 中,链表转树的阈值是多少?

目录
相关文章
|
运维 Cloud Native 安全
阿里平台工程的发展历程与关键实践
什么是平台工程,怎么在企业内落地平台工程,云效负责人陈鑫在2023云栖大会上,结合云效过去在阿里内部十多年的经验和在各大企业的实践,给出了非常详细的解答。
3795 3
|
自然语言处理 Java Go
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
Fury是一个基于JIT动态编译的多语言原生序列化框架,支持Java/Python/Golang/C++等语言,提供全自动的对象多语言/跨语言序列化能力,以及相比于别的框架最高20~200倍的性能。
Fury:一个基于JIT动态编译的高性能多语言原生序列化框架
vite.config.js中vite.defineConfig is not defined以及创建最新版本的vite项目
本文讨论了在配置Vite项目时遇到的`vite.defineConfig is not defined`错误,这通常是由于缺少必要的导入语句导致的。文章还涉及了如何创建最新版本的Vite项目以及如何处理`configEnv is not defined`的问题。
750 3
vite.config.js中vite.defineConfig is not defined以及创建最新版本的vite项目
|
存储 安全 Java
Java 泛型 详解
Java 泛型是 Java 5 引入的特性,允许在类、接口和方法中定义类型参数,提供类型安全、代码重用性和灵活性。泛型包括类型参数、泛型类和接口,以及泛型方法。通过定义类型参数如 `&lt;T&gt;`,可以在编译时检查类型,避免强制类型转换错误。泛型还支持类型边界和通配符,使代码更加灵活和高效。Java 集合框架广泛使用泛型实现类型安全的集合存储。理解泛型的基本概念和使用技巧有助于提高代码质量和可维护性。
239 4
lombok的使用
本文介绍了Lombok库的基本使用方法和常用注解,通过示例代码展示了如何使用Lombok简化Java对象的创建、属性访问、日志记录等编码工作,使代码更加简洁。
lombok的使用
|
移动开发 物联网 API
HTML6的最新消息
截至2023年10月,HTML6 仍处于提议和讨论阶段,尚未正式发布。W3C 和 WHATWG 等组织正不断迭代和改进 HTML 规范,采用“增量更新”策略。HTML6 的潜在新特性包括:改进的语义和结构元素、增强的 Web 组件支持、更强大的 API、多媒体功能升级、更好的可访问性和性能优化,以及对物联网的支持。这些改进将使开发者能够创建更复杂、高性能且符合无障碍标准的网页。然而,HTML 的发展是非线性的,新版本没有明确的发布时间,开发者应关注官方动态获取最新信息。
|
运维 Kubernetes Devops
平台工程:它是什么?谁来做?怎么做?
大家可能听说过平台工程,这是一个新术语,它为开发和 DevOps 领域中本已拥挤的角色集合增添了新内容。 在这篇文章中,我们将介绍平台工程、它与 DevOps 的区别以及为什么你可能考虑采用平台工程以及谁需要拥有平台工程的能力。
阿里云服务器带宽价格参考:选择1M、3M、5M、10M宽带价格解析
阿里云服务器1M、3M、5M、10M宽带需要多少钱?单说阿里云服务器宽带多少钱,而不确定云服务器实例规格及cpu和内存配置的话,是没办法具体说多少钱的,因为云服务器的价格受很多因素影响。本文将详细解析阿里云服务器在选择1M、3M、5M、10M不同带宽下的价格差异,以供大家参考。
阿里云服务器带宽价格参考:选择1M、3M、5M、10M宽带价格解析
|
运维 Kubernetes Cloud Native
云原生|kubernetes|minikube的部署安装完全手册(修订版)(一)
云原生|kubernetes|minikube的部署安装完全手册(修订版)
4566 0
云原生|kubernetes|minikube的部署安装完全手册(修订版)(一)