一,基本概念

Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值,即hashCode值.

在Java的Object类中有一个方法:

public native int hashCode();

根据这个方法的声明可知,该方法返回一个int类型的数值,并且是本地方法,因此在Object类中并没有给出具体的实现。

有些朋友误以为默认情况下,hashCode返回的就是对象的存储地址,事实上这种看法是不全面的,确实有些JVM在实现时是直接返回对象的存储地址,但是大多时候并不是这样,只能说可能存储地址有一定关联。

hashCode返回的并不一定是对象的(虚拟)内存地址,具体取决于运行时库和JVM的具体实现

二,hashCode与equals

在Java中hashCode的实现总是伴随着equals,他们是紧密配合的,你要是自己设计了其中一个,就要设计另外一个。当然在多数情况下,这两个方法是不用我们考虑的,直接使用默认方法就可以帮助我们解决很多问题。但是在有些情况,我们必须要自己动手来实现它,才能确保程序更好的运作。

对于equals,我们必须遵循如下规则:

对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

反射性:x.equals(x)必须返回是“true”。

类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。

一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

对于hashCode,我们应该遵循如下规则:

1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。

2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。

3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。

根据hashCode,equals所遵循的规则我们不难得出:

如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。

如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。

可以用一张流程图来描述 hashCode,equals是如何配合使用

java hash. javahashcode_java

`

整个处理流程是:

1、判断两个对象的hashcode是否相等,若不等,则认为两个对象不等,完毕,若相等,则比较equals。

2、若两个对象的equals不等,则可以认为两个对象不等,否则认为他们相等。

三,hashcode的作用

对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode。在Java中也一样,hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,提高查找效率.这样的散列集合包括HashSet、HashMap以及HashTable

实际场景:当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?(注意:集合中不允许重复的元素存在如Set集合)

解决办法:采用equals方法去逐一比较,效率必然是一个问题.此时就需要用hashcode和equals配置使用提高效率

根据第二章节hashcode,equals所遵循的规则以及配合使用的流程.

当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashcode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashcode值

1.    如果table中没有该hashcode值,即第一步的判断 hashcode是否相同结果为false ,表示没有与该对象相等的对象.它就可以直接存进去,不用再进行任何比较了

2.如果存在该hashcode值,进行第二步equals判断(因为根据hashcode规则不同对象可能具有相同的hashcode值),如果为true即对象相等,存在该对象就不保存.反之false不存在保存.

下面这段代码是java.util.HashMap的中put方法的具体实现:

public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}

hashCode重要么?不重要,对于List集合、数组而言,他就是一个累赘,但是对于HashMap、HashSet、HashTable而言,它变得异常重要。所以在使用HashMap、HashSet、HashTable时一定要注意hashCode。对于一个对象而言,其hashCode过程就是一个简单的Hash算法的实现,其实现过程对你实现对象的存取过程起到非常重要的作用。

四:参考文献