散列码是由对象导出的一个整数值。因为hashCode()定义在Object类中,因此每一个对象都有一个默认的散列值,为对象的存储地址。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能,HashMap对象是根据其Key的hashCode来获取对应的Value。
hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的
查看Object的hashCode函数,
public native int hashCode();
native是啥,简单查了下,写的比较杂,这里直接拷贝了别人的解释:
一个native方法就是一个Java调用非Java代码的接口,该方法由非Java语言实现
在定义一个native方法时,不提供实体(像是Java Interface),因为其实现在Java语言外
native是与C++联合开发的时候用的!java自己开发不用的!
使用native关键字说明这个方法是原生函数,也就是这个方法是用C/C++语言实现的,并且被编译成了DLL,由java去调用。这些函数的实现体在DLL中,JDK的源代码中并不包含,你应该是看不到的。对于不同的平台它们也是不同的。这也是java的底层机制,实际上java就是在不同的平台上调用不同的native方法实现对操作系统的访问的。
native的意思就是通知操作系统,这个函数你必须给我实现,因为我要使用。所以native关键字的函数都是操作系统实现的, java只能调用。
java是跨平台的语言,既然是跨了平台,所付出的代价就是牺牲一些对底层的控制,而java要实现对底层的控制,就需要一些其他语言的帮助,这个就是native的作用了
回到HashCode,就是说HashCode在不同平台下实现会不同,而且暂时我们看不到?
再看看String的hashCode函数,
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
为了验证是不是这么一回事,测试一下,这个hash默认的是0
那字符串“a”应该=31*0+a=97
“aa”=31*97+97=3104
“abc”=96354
测试了一下确实是的,但是问题来了,String长度增加时,hashCode岂不是迅速增大,一个int根本不够啊,测试了一个长字符串,返回的还是一个int(可能是负数),可能直接将多出的部分截断了,塞给了一个int型
再看一个几个实现:
public int hashCode() {
long bits = doubleToLongBits(value);
return (int)(bits ^ (bits >>> 32));
}Double
public int hashCode() {
return value;
}Integer
public int hashCode() {
return (int)value;
}Character
public native int hashCode();自定义类
不同的类型计算方法是不同的
同样的内容的字符串String得到的HashCode是一样的,因为String的hashCode是由内容得到的
而同样内容的StringBuilder之间得到的Hash值却不同,因为StringBuilder自己没有实现HashCode函数,返回的是Object默认的方法(返回对象存储地址)
如果重新定义了equals方法,就必须重新定义hashCode方法,以便于用户可以将对象插入到散列表中。(13章里面讲,我才看到第五章啊)
总之,如果x和y通过equals相等,那他们的hashCode也必须相等。
但是反过来不一定,只能说明在散列存储结构中,存放在一个篮子里,但是不一定equals
hashCode是用于查找使用的