A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 钟伟杰 中级黑马   /  2013-4-24 01:02  /  1343 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 钟伟杰 于 2013-4-24 10:26 编辑

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

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

评分

参与人数 1技术分 +1 收起 理由
张熙韬 + 1

查看全部评分

4 个回复

倒序浏览
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. }  
复制代码

评分

参与人数 1技术分 +1 收起 理由
张熙韬 + 1

查看全部评分

回复 使用道具 举报
HashSet是采用哈希算法存取对象的集合,它内部采用对某个数字n进行取余的方式对哈希码进行分组和划分对象的存储区域。
HashSet集合存储对象时,对象通过定义一个hashCode方法返回该对象自身的哈希码,而HashSet则根据这个哈希码确定对象在集合中的存放位置,这样可以很好地实现对象检索功能。
Object类中定义了一个hashCode()方法来返回每个Java对象的哈希码,当从HashSet集合中查找某个对象时,Java系统首先调用对象的hashCode()方法获得该对象的哈希码,然后根据哈希码找到相应的存储区域,最后取出该存储区域内的每个元素对该对象进行equals方法比较,这样不用遍历集合中的所有元素就可以得到结论。

评分

参与人数 1技术分 +1 收起 理由
张熙韬 + 1

查看全部评分

回复 使用道具 举报
简单点说,HashSet集合,采用的数据结构是哈希表,数据是虽机的,不能重复。

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

一般我们都要复写HashCode和equals这两个方法,设置比较条件,确保数据唯一。

评分

参与人数 1技术分 +1 收起 理由
张熙韬 + 1

查看全部评分

回复 使用道具 举报
本帖最后由 陈雨 于 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,这两者都是关于他们自己底层数据结构的运用。
要是还是不懂建议重复看视频

评分

参与人数 1技术分 +1 收起 理由
田磊阳 + 1

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马