详解Java中用于查找对象哈希码值的hashCode()函数
理解
hashcode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
hashcode() 定义在jdk的object.java中,这就意味着java中的任何类都包含有hashcode() 函数。
虽然,每个java类都包含hashcode() 函数。但是,仅仅当创建并某个“类的散列表”(关于“散列表”见下面说明)时,该类的hashcode() 才有用(作用是:确定该类的每一个对象在散列表中的位置;其它情况下(例如,创建类的单个对象,或者创建类的对象数组等等),类的hashcode() 没有作用。
上面的散列表,指的是:java集合中本质是散列表的类,如hashmap,hashtable,hashset。
也就是说:hashcode() 在散列表中才有用,在其它情况下没用。在散列表中hashcode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
我们都知道,散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!
散列表的本质是通过数组实现的。当我们要获取散列表中的某个“值”时,实际上是要获取数组中的某个位置的元素。而数组的位置,就是通过“键”来获取的;更进一步说,数组的位置,是通过“键”对应的散列码计算得到的。
下面,我们以hashset为例,来深入说明hashcode()的作用。
假设,hashset中已经有1000个元素。当插入第1001个元素时,需要怎么处理?因为hashset是set集合,它允许有重复元素。
“将第1001个元素逐个的和前面1000个元素进行比较”?显然,这个效率是相等低下的。散列表很好的解决了这个问题,它根据元素的散列码计算出元素在散列表中的位置,然后将元素插入该位置即可。对于相同的元素,自然是只保存了一个。
由此可知,若两个元素相等,它们的散列码一定相等;但反过来确不一定。在散列表中,
1、如果两个对象相等,那么它们的hashcode()值一定要相同;
2、如果两个对象hashcode()相等,它们并不一定相等。
注意:这是在散列表中的情况。在非散列表中一定如此!
示例
我们来看一个具体的示例吧,
public class hashtest { private int i; public int geti() { return i; } public void seti(int i) { this.i = i; } public int hashcode() { return i % 10; } public final static void main(string[] args) { hashtest a = new hashtest(); hashtest b = new hashtest(); a.seti(1); b.seti(1); set<hashtest> set = new hashset<hashtest>(); set.add(a); set.add(b); system.out.println(a.hashcode() == b.hashcode()); system.out.println(a.equals(b)); system.out.println(set); } }
这个输出的结果:
true false [com.ubs.sae.test.hashtest@1, com.ubs.sae.test.hashtest@1]
以上这个示例,我们只是重写了hashcode方法,从上面的结果可以看出,虽然两个对象的hashcode相等,但是实际上两个对象并不是相等;,我们没有重写equals方法,那么就会调用object默认的equals方法,是比较两个对象的引用是不是相同,显示这是两个不同的对象,两个对象的引用肯定是不定的。这里我们将生成的对象放到了hashset中,而hashset中只能够存放唯一的对象,也就是相同的(适用于equals方法)的对象只会存放一个,但是这里实际上是两个对象a,b都被放到了hashset中,这样hashset就失去了他本身的意义了。
此时我们把equals方法给加上:
public class hashtest { private int i; public int geti() { return i; } public void seti(int i) { this.i = i; } <span style="color:#3366ff;"><strong>public boolean equals(object object) { if (object == null) { return false; } if (object == this) { return true; } if (!(object instanceof hashtest)) { return false; } hashtest other = (hashtest) object; if (other.geti() == this.geti()) { return true; } return false; }</strong></span> public int hashcode() { return i % 10; } public final static void main(string[] args) { hashtest a = new hashtest(); hashtest b = new hashtest(); a.seti(1); b.seti(1); set<hashtest> set = new hashset<hashtest>(); set.add(a); set.add(b); system.out.println(a.hashcode() == b.hashcode()); system.out.println(a.equals(b)); system.out.println(set); } }
此时得到的结果就会如下:
true true [com.ubs.sae.test.hashtest@1]
从结果我们可以看出,现在两个对象就完全相等了,hashset中也只存放了一份对象。
总结
1、hashcode的存在主要是用于查找的快捷性,如hashtable,hashmap等,hashcode是用来在散列存储结构中确定对象的存储地址的;
2、如果两个对象相同,就是适用于equals(java.lang.object) 方法,那么这两个对象的hashcode一定要相同;
3、如果对象的equals方法被重写,那么对象的hashcode也尽量重写,并且产生hashcode使用的对象,一定要和equals方法中使用的一致,否则就会违反上面提到的第2点;
4、两个对象的hashcode相同,并不一定表示两个对象就相同,也就是不一定适用于equals(java.lang.object) 方法,只能够说明这两个对象在散列存储结构中,如hashtable,他们“存放在同一个篮子里”。
上一篇: 网络编程概述