Hash Code 散列码


散列码(hash code)散列码是由对象的实例域产生的一个整数。更准确的说,具有不同数据域的对象将产生不同的散列码。散列码是没有规律的。如果 x 和 y 是两个不同的对象,x.hashCode() 与 y.hashCode() 基本上不会相同。

hashCode() 方法

hashCode() 方法就是获取该对象散列码的方法,hashCode() 方法定义在 Object 类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址。
但是很多类都需要重写获取散列码的方法,例如:String 类中使用下面的算法计算散列码(散列函数):

int hash;//默认为 0
public int hashCode() {
       int h = hash;
       if (h == 0 && value.length > 0) {//这里计算 hash code
           char val[] = value;
           for (int i = 0; i < value.length; i++) {
               h = 31 * h + val[i];
           }
           hash = h;
       }
       return h;
   }

计算字符串散列码的公式为:
$ h = val[0]·31^(L-1) + … + val[L-3]·31^2 + val[L-2]·31^1 + val[L-1]·31^0 $
举个例子,获取 “call” 的散列码:
字符 c 对应的 unicode 为 99,a 对应的 unicode 为 97,l 对应的 unicode 为 108,所以字符串 “call” 的哈希值为
$ 3045982 = 99 · 31^3 + 97 · 31^2 + 108 · 31^1 + 108 · 31 = 108 + 31 · (108 + 31 · (97 + 31 · 99)) $

由于 hashCode 方法定义在 Object 类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址。通过下面这段代码对比一下 String 和 StringBuilder 的散列码:

String s = "Ok";
StringBuilder sb = new StringBuilder(s);
System.out.println(s.hashCode() + " " + sb.hashCode());//输出 2556 366712642
String t = new String("Ok");
StringBuilder tb = new StringBuilder(t);
System.out.println(t.hashCode() + " " + tb.hashCode());//输出 2556 1829164700
对象 散列码
s 2556
sb 366712642
t 2556
tb 1829164700

可以看到,字符串 s 与 t 拥有相同的散列码,这是因为字符串的散列码是由内容计算的,而 StringBuilder 类的 sb 和 tb 却有着不同的散列码,这是因为在 StringBuilder 类中没有定义 hashCode 方法,所以它的散列码是由 Object 类默认的 hashCode 方法导出的对象存储地址。

equals 与 hashCode 的定义必须一致:如果 x.queals(y) 返回 true,那么 x.hashCode 就必须与 y.hashCode() 具有相同的值。

equals()相等的两个对象,hashcode()一定相等;
equals()不相等的两个对象,hashcode()可能相等,也可能不等。

反过来:hashcode()不等,一定能推出 equals()也不等;hashcode()相等,equals()可能相等,也可能不等。


文章作者: CrazyBunQnQ
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 CrazyBunQnQ !
 上一篇
HashSet 散列集 HashSet 散列集
链表和数组可以按照人们的意愿排列元素的次序,但是如果想要查看某个指定的元素,却又忘记了它的位置,就需要访问所有元素,直到找到为止。如果集合中包含的元素很多,将会消耗很多时间。
2017-03-19
下一篇 
集合 集合
在实际开发中,经常需要将使用的对象存储于特定数据结构中。Java 提供了这样的容器:数组与集合,但是数组是定长的,操作数据过于繁琐,所以今天在这里介绍下集合。
2017-03-17
  目录