http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E9%87%8C%E9%9D%A2%E7%9A%84hashcode-string-hashcode/
前一篇文章说了Object.hashcode(),现在来看下String.hashcode(), 因为很多情况下HashMap和HashTable的key是String;
下面是jdk里面的代码和注释
Returns a hash code for this string. The hash code for a String object is computed as
s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]
using int arithmetic, where s[i] is the ith character of the string, n is the length of the string, and ^ indicates exponentiation. (The hash value of the empty string is zero.)
public int hashCode() {
int h = hash;
int len = count;
if (h == 0 && len > 0) {
int off = offset;
char val[] = value;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
这个意思是说
1. String.Hashcode()的算法是s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1],就是每个字符的ascii值以质数31作为进制计算后得到的结果就是,相当于31进制;
实际的计算过程是从左向右计算,每移一位对之前算的值乘以31
2. 同时,有个成员变量hash保存了计算过的hashcode(), 第一次调用String.hashcode() 后,计算出来的hashcode()就保存在hash成员变量中,以后就直接返回了; 当然,这里有个特殊的地方是String是常量,就是创建以后值就不再变了, “Strings are constant; their values cannot be changed after they are created.”, 这是jdk里面的说明;所以他的hashcode()也永远不会变化,可以缓存在成员变量里面
3. 既然String.hashcode()的算法已经明确了,那么就可以尝试构造冲突,
假设两个字符串都是有两个字符,那么如果满足 a1*31+b1 = a2*31 +b2这个等式,这两个字符串的hashcode()就一样
也就是(a1-a2)*31=b2-b1 ,如果设a1-a2=1, 那么b2-b1=31就好, ascii表里面满足这个等式的字符串可以找出很多来, 下面是一段测试代码
public void testHash()
{
System.out.println("A:" + (int)'A');
System.out.println("B:" + (int)'B');
System.out.println("a:" + (int)'a');
System.out.println("Aa".hashCode() + "," + "BB".hashCode());
System.out.println("Ba".hashCode() + "," + "CB".hashCode());
System.out.println("Ca".hashCode() + "," + "DB".hashCode());
System.out.println("Da".hashCode() + "," + "EB".hashCode());
}
打印的结果
A:65
B:66
a:97
2112,2112
2143,2143
2174,2174
2205,2205
可以看到,这些字符串都满足上面的等式,都发生了hashcode()冲突的情况; 并且,只要按照上面的方法,可以构造出很多两个字符串的冲突来;
更进一步,假设两个字符串都有4个字符串,按照公式,假设前两个字符串产生hashcode为m, 后两个字符串产生hashcode为n,
那么,4个字符串的hashcode是m*31^2+n, 所以,如果两个字符串组成的hashcode()是一样的,那么4个字符串组成的hashcode也是一样的!
所以,”AaAa”, “BBBB”,”AaBB”,”BBAa”的hashcode都一样,都是2031744,
而”CaDB”,”CaCa”,”DBCa”,”DBDB”的hashcode都一样,是2091388;
并且按照这个方法,可以构造6个字符串,8个字符串等hashcode相同的字符串来;
去年的hash冲突导致dos攻击的漏洞,基本就可以按照这个方法构造错误
酷壳的Hash Collision DoS 问题里面也详细说明了当时的情况,不过陈浩举例的hash函数其实是HashMap的hash函数,
那个其实是对已经产生的hashcode()做二次hash,并不是String.hashcode()的代码,
可能读者看那个代码和后续的说明不能直接看明白为什么Aa和BB的hash值是一样的,也不知道为什么进一步可以得出AaBB和AaAa的hash值也一样的
相信读者看了这篇文章应该会清楚了
当然,陈浩的技术很好,我一直都很喜欢看他的文章
分享到:
相关推荐
安装npm install string-hashcode 例子var hashCode = require ( 'string-hashcode' ) ;var s = 'abc' ;console . log ( s . hashCode ) ; // undefinedvar code = hashCode ( s ) ;console . log ( s . hashCode ) ...
Hashcode是Java编程语言中一个非常重要的概念,它在equals方法中扮演着关键角色。在Java中,每个对象都具有一个独特的Hashcode,它可以用来标识对象的身份。但是Hashcode是什么?它是如何产生的?有什么作用?下面...
HashCode 是 Java 中一个重要的概念,它用于标识对象的唯一性。然而,Hash Code 有可能重复,这会导致程序出错。下面我们将深入探讨 Java 中 HashCode 重复的可能性。 首先,让我们了解什么是 Hash Code。Hash ...
在Java编程语言中,`hashCode()`与`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及在Java集合框架...
在Java编程语言中,`String`类是使用最频繁的类之一,它代表不可变的字符序列。本文将深入解析`String`类的一些常用方法,帮助开发者更好地理解和使用这个核心类。 1. **构造方法** - `String()`:创建一个空字符...
Java编程语言的基础构建块之一是`java.lang`包,它被自动导入到每个Java程序中,无需显式导入。这个包包含了许多核心类和接口,是编写任何Java应用程序不可或缺的部分。`java.lang`包中最基本的类是`Object`,它是...
#### 一、`hashCode` `hashCode` 方法是 `Object` 类中的一个方法,用于返回对象的哈希码值。在 Java 中,哈希码经常被用于实现散列表(如 `HashMap` 和 `HashSet`)。为了确保散列表的正确性,重写 `equals` 方法...
Java中String类的hashCode方法采用特定的算法,即:初始时,哈希码值为0,然后以字符为单位,对于字符串中的每一个字符,都使用31乘以当前哈希码,然后加上当前字符的ASCII值,然后更新哈希码。 2. **JavaScript中...
17.SetAndList.java set的简单操作极其hashcode应用 18.Singleton.java java设计模式之单例模式 19.Factory.java 设计模式之工厂模式 20.Swing.java 介绍了java的图形应用 --课程包括了java SE的大部分常用类...
在Java编程语言中,`hashCode()`和`equals()`方法是非常重要的概念,它们不仅对于深入理解Java内存管理至关重要,也是实现自定义类的关键部分之一。本文将详细介绍这两个方法的工作原理、使用场景以及它们之间的关系...
hashCode方法的实现方式有多种,String类的hashCode方法就是一个典型的例子,它使用数学表达式s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]来计算hashCode值,其中s[i]是字符串的第i个字符,n是字符串的长度。...
在Java中,`String`类是一个非常重要的类,它提供了丰富的功能用于处理文本数据。`String`类是不可变的(immutable),这意味着一旦一个`String`对象被创建,它的内容就不能被改变。这种特性使得`String`类非常适合...
equals 方法和 hashCode 方法是 Java 语言中两个重要的方法,它们都是在 Object 类中定义的。equals 方法用于比较两个对象是否相等,而 hashCode 方法用于返回对象的哈希码。 在 Java 的 Object 类中,equals 方法...
Java 中 equals、hashcode 和==的区别是 Java 编程语言中一个经常遇到的问题。这三个概念都是用来比较对象的,但是它们之间存在着本质的区别。 首先,==号是Java中的一个运算符,用于比较两个对象的内存地址是否...
Java语言提供了多种常用包,包括java.lang、String、StringBuffer、Math、Object、Class、Constructor、Method、Field、Date、Calendar、SimpleDateFormat、File等。这些包中的类和方法为Java开发提供了强大的支持。...
hashCode方法是Java中Object类的一个方法,用于计算出对象的一个散列值,用于判断在集合中对象是否重复的关键。hashCode方法是一个本地方法,无法在Java代码中实现。 一条重要的定理是:equals相同的对象,hashCode...
在Java编程语言中,`String`类是使用最广泛的类之一,主要用来处理文本字符串。字符串在Java中被视为不可变对象,这意味着一旦创建了一个`String`对象,就不能更改它的值。下面我们将深入探讨`String`类的一些关键...
总的来说,理解并正确使用`equals()`和`hashCode()`方法对于编写高质量的Java代码至关重要,尤其是在处理集合框架中的对象时。这两个方法的合理实现能确保对象比较的正确性和哈希表操作的效率。希望这个深入解析能...