黑马程序员技术交流社区

标题: hashCode问题 [打印本页]

作者: 钟伟杰    时间: 2013-4-24 01:02
标题: hashCode问题
本帖最后由 钟伟杰 于 2013-4-24 10:26 编辑

HashSet存储对象时为什么要定义一个hashCode方法:
class Person
{
............
public int hashCode()
{
       return name.hashCode()+nun*78;
}
................
}

不是每次new一个对象都会产生一个哈希值的吗?这个方法是有什么用呢?


作者: 陈湘林    时间: 2013-4-24 01:20
HashCode和HashSet
当对象存储到Hash集合里是,应该重写该对象所在类的hashcode方法,如果不用储存到hash集合中则可以不重写hashcode方法。重写的原则是:当x.equals(y)时,它们所对应的hashcode也应该相等,即:x.hashcode()==y.hashcode()为true。
一个HashSet的例子:
HashSet是一个无序不可以重复储存的集合。那么HashSet是如何判断两个对象是否重复呢?答案是靠它们的hashcode方法,如果对应的两个对象所返回的hashcode方法的值是相等的,则表明该两个对象“相等”。所以一般情况下,用户需要对要储存到HashSet的对象所在的类重写hashcode方法,而不是用继承自Object的hashcode方法,因为Object 类定义的 hashCode 方法会针对不同的对象返回不同的整数(这一般是通过将该对象的内部地址转换成一个整数来实现的),一般不符合用户的需求。
要想在HashSet中知道对象的位置,就要先计算该对象的hashcode,然后与散列表的列表的总数取余,所得结果就是保存这个元素的列表的索引。
当一个对象被储存进HashSet集合后,就不能再修改这个对象中的那些参与计算hashcode值的属性了,否则对象修改后的hashcode与最初储存到HashSet的值不一致,在这种情况下,即使在contains方法中使用该对象的当前引用作为参数区HashSet集合中检索对象,也将返回不到对象的结果,这也会导致无法从HashSet集合中单独删除当前对象,从而造成内存泄露。为什么会杀不了呢:因为,当集合调用remove方法的时候,会从对象得到hashcode,但是原先对象储存的时候所对应的hashcode不是现在的hashcode,所以定位的不是相同的对象,因此删除不了。
所谓内存泄露是指该对象已经不需要再用,但是一直占着内存空间。
  1. package April;  
  2.   
  3. import java.util.Collection;  
  4. import java.util.Date;  
  5. import java.util.HashSet;  
  6.   
  7. public class HashSetTest {  
  8.     public static void main(String[] args) {  
  9.         Collection c = new HashSet();  
  10.         Date d = new Date();  
  11.         try {  
  12.             Thread.sleep(500);//控制时间  
  13.         } catch (InterruptedException e) {  
  14.             e.printStackTrace();  
  15.         }  
  16.         Person p1 = new Person("p1",23,d);  
  17.         Person p2 = new Person("p2",23,new Date());  
  18.         Person p3 = new Person("p3",23,new Date());  
  19.         c.add(p1);  
  20.         c.add(p2);  
  21.         c.add(p3);  
  22.         p1.setName("p4");  
  23.         c.remove(p1);  
  24.         System.out.println(c.size());//size的值依然是3  
  25.     }  
  26. }  
复制代码

作者: 翟宝海    时间: 2013-4-24 06:28
HashSet是采用哈希算法存取对象的集合,它内部采用对某个数字n进行取余的方式对哈希码进行分组和划分对象的存储区域。
HashSet集合存储对象时,对象通过定义一个hashCode方法返回该对象自身的哈希码,而HashSet则根据这个哈希码确定对象在集合中的存放位置,这样可以很好地实现对象检索功能。
Object类中定义了一个hashCode()方法来返回每个Java对象的哈希码,当从HashSet集合中查找某个对象时,Java系统首先调用对象的hashCode()方法获得该对象的哈希码,然后根据哈希码找到相应的存储区域,最后取出该存储区域内的每个元素对该对象进行equals方法比较,这样不用遍历集合中的所有元素就可以得到结论。
作者: lipingan0520    时间: 2013-4-24 07:00
简单点说,HashSet集合,采用的数据结构是哈希表,数据是虽机的,不能重复。

然尔不能重复的依据就是底层调用HashCode,比较地址是否相同,如果相同在调用equals方法,进行地址比较

一般我们都要复写HashCode和equals这两个方法,设置比较条件,确保数据唯一。
作者: 陈雨    时间: 2013-4-24 09:37
本帖最后由 陈雨 于 2013-4-24 09:39 编辑

你用hashSet往里面添加对象时,HashSet底层会自动调用hashcode()方法,给对象赋地址值,因为都是新建对象所以每个地址都会不一样。但是你想比较是否添加了重复元素,比如姓名和年龄相同时就是重复。因为你添加对象时都是new的,所以地址值肯定不一样,地址值不一样就不会调用equals()。这里要注意的是,比如往HashSe里add一个new Person,这个Person是继承Object的它当中有equals()方法它比较的也是地址值,所以你要复写equals方法,让他变成对象比较的方法。
总结:给对象赋值hashcode(),若hashcode不同则不会调用equals方法,若hashcode相同,才会调用equals方法,进行进一步内容比较,若还是相同则不添加。contains和remove也是这用的这个原理。你这里定义hashcode()方法,就是为了按照你的规则,来调用equals()方法判断是否添加重复元素。后面的TreeSet也是一样的,比较对象是否相同用的是compareTo和return 0,这两者都是关于他们自己底层数据结构的运用。
要是还是不懂建议重复看视频




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2