黑马程序员技术交流社区
标题: HashSet问题 [打印本页]
作者: 王广彬 时间: 2012-8-12 22:24
标题: HashSet问题
package cn.set;
importjava.util.HashSet;
importjava.util.Iterator;
// 往hashSet集合中存入自定义对象.如果姓名和年龄相同的为同一个人,删除
class Person{
private String name;
private int age;
public Person(String name,int age){
this.setName(name);
this.setAge(age);
}
public int hashCode(){ //hashCode()有什么用?是在什么时候调用?
return name.hashCode()+age; //返回name.hashCode()+age;又是什么意思啊?
} //看不明白能不能给解释一下?
public boolean equals(Object obj){ //判断对象是否相同
if(!(obj instanceof Person)){
return false;
}
Person p=(Person)obj;
//System.out.println(this.name+".........."+p.name);
returnthis.name.equals(p.name)&&this.age==p.age;
}
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
returnname;
}
public int getAge(){
return age;
}
}
public classHashSetDemo1 {
public static void main(String[] args){
HashSet hset=new HashSet();
hset.add(new Person("黄晓明",21));
hset.add(new Person("周星驰",23));
hset.add(new Person("陈小春",22));
hset.add(new Person("周星驰",23));
hset=deleteSameElement(hset); //把去除重复元素后的集合赋给hset
for(Iteratorit=hset.iterator();it.hasNext();){
Person p=(Person)it.next();
sop(p.getName()+"==="+p.getAge());
}
}
public static HashSet deleteSameElement(HashSethash){
HashSet haha=new HashSet();
for(Iteratorit=hash.iterator();it.hasNext();){
Object obj=it.next();
if(!(haha.contains(obj))){
haha.add(obj);
}
}
return haha;
}
public static void sop(Object obj){
System.out.println(obj);
}
}
各位大侠,今天看视频这段代码有点费解,就是红色字体那段,hashCode是怎么用的?程序在运行时什么时候调用它啊?能不能给解释一下,看不懂,谢谢!
作者: 张雪磊 时间: 2012-8-12 22:43
Set集合判断元素重复的方法,hashCode和equals
equals里面定义了如何判断两个Set集合元素是否相等。
具体的说由于Set集合里的元素是不重复的,那当加入一个新元素就需要那这个元素与集合里的其他元素作比较,如果集合中已存在要加入的元素,也就是符合自己定义的equals里的判断方式,那就不会添加这个元素,以保证集合里的成员唯一。
hashCode的作用也是保证Set集合里成员唯一,而且是先判断hashCode的值是否相等,如果相等在判断equals是否相等,如果都相等,那说明集合中已经存在相同成员了。至于为什么 要写成 i = 10 * i + age; 先要说说这句代码要做什么,就拿上面的1,2两个对象来说,i 就是那两个对象中jack对应的hash值,都是jack所以这两个是相同的,在加上age,都是20当然也相等了。但有一种特殊情况,假如有这样两个对象
new Person("Jack", 20));
new Person("Jahn",50));
这两个肯定不相等,但恰好jack对应的hash值是50,jahn的hash值是20。20+50=50+20,这样本来不应该相等的两个元素,却被判断为相等。所以年龄乘以随便一个数就可以避免这种情况发生。
作者: 王广彬 时间: 2012-8-12 23:14
哦,那么hashCode方法是在什么时候调用的?主方法中没看到被调用啊?
作者: 郑正华 时间: 2012-8-13 01:14
首先我要说下,这里很多人都存在疑惑,不知道这样做是为什么,思路也很难理清,希望楼主能够实实在在的理解了其中的道理;
hashSet保证元素唯一性的原理:判断元素的hashCode值是否相同,如果相同,还会继续判断元素的equals方法,是否为true;
因为HashSet集合是根据对象的地址值来存放对象的,而对象的地址值是根据哈希算法得来的,默认情况下(就是不覆写Object的hashCode方法)是调用windows底层的一个哈希算法。
Object的原始的hashCode()方法中是将对象的内存地址值作为实例的哈希值,因此在使用Set的时候就一定要覆写hashCode()方法。
为什么要覆写呢?原因是Set在add一个新对象的时候并不是将这个新对象与Set内的对象逐一通过equals()进行比较,而是先比较新对象与Set内的对象的哈希值以区分新对象是否重复,因为Set中不允许存在重复元素。比如你的代码中new了四个Persont类的新对象:
hset.add(new Person("黄晓明",21)); hset.add(new Person("周星驰",23));
hset.add(new Person("陈小春",22));
hset.add(new Person("周星驰",23));
在添加第四个人的时候,你肯定希望这个人无法被添加,因为上面已经添加了相同的人;
如果你不覆写Person类的hashCode()方法,那么此时第四个人是可以被添加的,因为第四个人和第二个人的内存地址不同,所以要覆写hashCode()方法,生成Person类自己独有的哈希值,怎么覆写呢?这就应该根据你的判断条件来生成相应的哈希值。你的判断条件就是姓名相同、年龄也相同,那就是同一个人!
那么这里为什么要返回:name.hashCode()+age;
这里要说下,因为name是String类型,String类中也有hashCode方法,所以name.hashCode()返回的也是一个int类型,这个int类型的哈希值加上年龄不就生成每个对象独有的哈希值了么。你添加的姓名或年龄中只要有一样不相同,那name.hashCode()+age;返回的int类型的值肯定也不相同。
再仔细想想,是不是有这样一种情况:如果有些人姓名不同,年龄也不同,但是经过 name.hashCode()+age 算下来之后,哈希值竟然相同!结果呢?还要继续调用equals方法进行内容比较,你说,本来就不是同一个人,还要再进一步去比较,多麻烦啊,效率自然也就不会高了,虽然这种情况少见,但也要预防,尽最大努力让每个对象的哈希值唯一!所以,毕老师视频中他就把age又乘了个整数,比如37:name.hashCode()+age*37;数学上有这样一个道理:在越大的范围内,两个数相同的概率就越小!这样的话把结果放大后,你看上面那种情况出现的概率是不是就要低很多了呀!
作者: 郑正华 时间: 2012-8-13 01:17
王广彬 发表于 2012-8-12 23:14 
哦,那么hashCode方法是在什么时候调用的?主方法中没看到被调用啊?
hashCode方法是在你往set集合中add对象时自动调用的,set集合的元素为什么不可以重复,就是因为在add对象时进行了相关的比较操作(调用hashCode和equals方法)~
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |