`
yde986
  • 浏览: 97865 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

详解 HashCode

 
阅读更多

hashcode的作用就是为了快速查找集合中是否存在重复元素。它是配合euqals方法使用的。

先简要介绍equals方法:在object中此方法比较两个对象的地址是不是相等。api中的一些类重写了此方法,如String重写了此方法(但StringBuffer没有重写此方法),比较的是两个字符串的内容是不是相等。因此我们在定义一个对象的时候也可以重写equals方法,按照我们的原则来定义。

再看一个问题:
为什么重写了equals方法需要重写hashcode方法?
答:为了更快判断集合中是否已存在某对象。对于链表和数组,如果我们要查找某个元素是否已经存在,我们需要遍历数组和链表,直到找到这个元素位置,这样很耗时间(事实上,链表和数组在加入一个元素时也没有判断它是否存在,因此可以有重复)。如果我们使用哈希表,我们就可以根据这个元素的hashcode方法和equals方法快速判断集合中是否已存在某对象。下面对此进行描述:

哈希表由哈希表元地址和哈希表元组成,是一个链表的数组。在java中,哈希码就是根据对象的hashcode方法产生的哈希码(hashcode一般是根据对象的成员变量生成哈希码)。一般而言,不同的对象有不同的hashcode,但也可能不同的对象拥有同一个哈希码。但是哈希表元地址是如何与哈希码匹配的呢?举个例子吧:
假设现在有16个哈希表元,那么哈希表元地址则为1到16,然后现在有个对象的哈希码为329,329%16=9,则这个对象就存储在哈希表元地址为9的哈希表元上。假设现在又有一个对象的哈希码为25,25%16=9,好的,由于哈希地址为9的哈希表元上已经有元素了,这时新存进来的对象就要遍历这个哈希表元(不是全部元素),通过equals方法判断这个哈希表元上是否已经存在相同对象,如果不存在,就继续存储在哈希表元的后面。
总结如下:每要添加一个对象,都是先获取它的hashcode值,然后一次就匹配了哈希表元地址,如果哈希表元上还没有存储对象,就直接存储,如果已经有了就遍历哈希表元(通过equals方法判断是否有相同对象存在),如果不存在相同对象就存储在哈希表元后面。


现在我们来看看HashSet的add方法,当add一个对象时,会根据这个对象生成的hashcode值快速到链表数组中匹配对应的哈希表元,如果哈希表元为空的,就可以把对象插入哈希表元中,然后返回true。如果哈希表元中已经有元素,这时就要遍历这个哈希表元(记住,只是遍历其中一个哈希表元,而不是集合中的所有元素,可能就一两个元素),通过equals方法来判断是否已经有相同的对象存在,如果有则返回false,如果没有则找空间存贮对象并链接到这个哈希表元的后面。
看完这里应该就明白了为什么重写equals方法还要重写hashcode方法,就是为了快速查找集合中是否存在重复元素。
记住一个原则:如果a.equals(b)为true时,a和b必须拥有相同的hashcode。

举个例子说明:

Java代码 复制代码
  1. public class Person {   
  2.     private String name;   
  3.     private int age;   
  4.   
  5.     @Override  
  6.     public int hashCode() {   
  7.         return age+name.hashCode();   
  8.     }   
  9.     @Override  
  10.     public boolean equals(Object obj) {   
  11.         if (this == obj)   
  12.             return true;   
  13.         if (obj == null)   
  14.             return false;   
  15.         if (getClass() != obj.getClass())   
  16.             return false;   
  17.         Test3 other = (Test3) obj;   
  18.         if (age != other.age)   
  19.             return false;   
  20.         if (name == null) {   
  21.             if (other.name != null)   
  22.                 return false;   
  23.         } else if (!name.equals(other.name))   
  24.             return false;   
  25.         return true;   
  26.     }    
  27. }  
Java代码 复制代码
  1. Person p1 = new Person();   
  2. Person p2 = new Person();  

我们上述实现的equals方法和hashcode方法必须满足下面条件:
1. p1.equals(p2)为true时,p1和p2必须拥有相同的哈希码。
2. p1和p2拥有相同的哈希码时,p1.equals(p2)不一定为true。

对于第二点我们可以设想一下:

Java代码 复制代码
  1. p1.age=24; p1.name.hashcode=109;   
  2. p2.age=27;p2.name.hashcode=106;  


因此p1和p2的hashcode相同,但p1.equals(p2)为false。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics