hashCode、hashCode()与HashSet集合
2010-01-25 22:58:43| 分类: Java Se | 标签: |字号大中小 订阅
hashCode
当使用toString方法的时候返回一个 "类型名@#$%#^%$ "的东西,比如一个****@4e57de。"@ "前面的是你的类名,后面的就是散列码的16进制表示。
hashCode 叫哈希代码或称散列码,简单的说就是通过哈希算法算出来的一大窜数字之类的东西和内存有关。默认的实现是将对象内部地址转化为整数作为HashCode,这当然能保证每个对象具有不同的HasCode,因为不同的对象内部地址肯定不同(废话)。因此你可以简单理解为对象在内存中的地址 担不是绝对物理地址。
hashCode()
Java中的集合(Collection)有两类,一类是List,再有一类是Set。前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。
那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?
当我们向HashSet集合中添加元素时,它是按hash算法来存储集合中的元素。首先HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该hashCode值决定该对象在HashSet中的存储位置。如果两个元素通过equals方法比较返回true,但它们的hashCode()方法返回值不相等,HashSet将会把它们存储在不同位置,也就添加成功。
简单的说,HashSet集合判断两个元素的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。看下面例子:
import java.util.*;
//类A的equals方法总是返回true,但没有重写其hashCode()方法
class A{
public boolean equals(Object obj){
return true;
}
}
//类B的hashCode()方法总是返回1,但没有重写其equals()方法
class B{
public int hashCode(){
return 1;
}
}
//类C的hashCode()方法总是返回2,但没有重写其equals()方法
class C{
public int hashCode() {
return 2;
}
public boolean equals(Object obj) {
return true;
}
}
public class TestHashSet{
public static void main(String[] args){
HashSet books = new HashSet();
//分别向books集合中添加2个A对象,2个B对象,2个C对象
books.add(new A());
books.add(new A());
books.add(new B());
books.add(new B());
books.add(new C());
books.add(new C());
System.out.println(books);
}
}
运行上面的程序,看到如下运行结果:
[B@1,B@1,C@2,A@c17164, A@de6ced]
从上面的程序可以看出,即使两个A对象通过equals比较返回true,但HashSet依然把它们当成2个对象;即使2个B对象的hashCode()返回相同的值(都是1),HashSet依然会把它们当成2个对象。
总结:如果需要某个类的对象保存到HashSet集合中,重写这个类的equals()方法和hashCode()方法,应该尽量保证两个对象通过equals比较返回true时,它们的hashCode方法返回值也是相等.
为什么会先调hashCode()方法呢?
大家可以想想,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。
通过hashCode()方法返回的是hashcode码。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode()方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。