您的位置:首页 > 其它

Hashset散列表

2016-04-27 22:23 423 查看


什么是HashSet?

HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。

equals()和hashCode()区别?

equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。

hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
之所以有hashCode方法,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如HashTable。

两个obj,如果equals()相等,hashCode()一定相等。

两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。

所以:

可以考虑在集合中,判断两个对象是否相等的规则是:

第一步,如果hashCode()相等,则查看第二步,否则不相等;

第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。

首先equals()和hashcode()这两个方法都是从object类中继承过来的。

equals()是对两个对象的地址值进行的比较(即比较引用是否相同)。

hashCode()是一个本地方法,它的实现是根据本地机器相关的。

object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出利用equals比较八大包装对象
(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它自定义对象时都是比较的引用地址
hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。
这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象,
当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,如在存储散列集合时(如Set类),将会存储了两个值一样的对象,
导致混淆,因此,就也需要重写hashcode()

总而言之,在重写equals()同时,也要重写hashCode()方法

例子:

//重新equals()方法,只有两者的id和name都相同,才认为为同一居民
public boolean equals(Object obj)
{
if(obj instanceof Resident)
{
Resident r = (Resident) obj;
if(r.id.equals(this.id) && r.name.equals(this.name))
return true;
}
return false;
}
//重写hashCode()方法,注意HashCode()的覆盖原则
public int hashCode()
{
return name.hashCode()^id.hashCode();
}


下面是一个人口普查表(HashSet)

package ch7;

import java.util.HashSet;
import java.util.Iterator;

public class Resident {
private String id;
private String name;
public Resident() {} //无参构造
public Resident(String id,String name) //有参构造
{
this.id=id;
this.name=name;
}
public void setName(String name)
{
this.name=name;
}
public String getName()
{
return name;
}
public void setId(String id)
{
this.id=id;
}
public String getId()
{
return id;
}
//重新equals()方法,只有两者的id和name都相同,才认为为同一居民 public boolean equals(Object obj) { if(obj instanceof Resident) { Resident r = (Resident) obj; if(r.id.equals(this.id) && r.name.equals(this.name)) return true; } return false; } //重写hashCode()方法,注意HashCode()的覆盖原则 public int hashCode() { return name.hashCode()^id.hashCode(); }
public String toString()
{
return "身份证号"+id+"姓名"+name;
}
public static void main(String[] args) {
//构建空的set,默认初始容量是16,加载因子0.75
HashSet<Resident> set = new HashSet<Resident>();
//构建空的set,指定初始容量为100,默认加载因子0.75
//HashSet<Resident> set1 = new HashSet<Resident>(100);
//构建空的set,指定初始容量为100,指定加载因子0.70
//HashSet<Resident> set2 = new HashSet<Resident>(100,0.70F);
//居委会交到公安局10条信息
Resident r1 = new Resident("100000","lily");
Resident r2 = new Resident("200000","jim");
Resident r3 = new Resident("300000","beake");
Resident r4 = new Resident("400000","hevey");
Resident r5 = new Resident("500000","deke");
Resident r6 = new Resident("600000","salory");
//r7与r2身份证号码相同,但名字不同,不是同一人,可以加入集合
Resident r7 = new Resident("200000","andy");
//r8与r5身份证号码相同,但名字不同,
Resident r8 = new Resident("500000","mike");
//r9与r1名字相同,但身份证号码不同,不是同一人,可以加入集合
Resident r9 = new Resident("900000","lily");
//r10与r3完全相同,是同一人信息,无法加入集合
Resident r10 = new Resident("300000","beake");
Resident r11 = new Resident("1100000","liyang");
//向集合中加入对象
set.add(r1);
set.add(r2);
set.add(r3);
set.add(r4);
set.add(r5);
set.add(r6);
set.add(r7);//可以加入集合
set.add(r8);//可以加入集合
set.add(r9);//可以加入集合
set.add(r10);//r10信息与r3相同,属无效信息,无法加入set中。
System.out.println("共收集到"+set.size()+"条有效信息如下:");
int i=1;
for(Resident r:set)
{
System.out.println("第"+i+"条信息"+r);
i++;
}
System.out.println("**********************");
//身份证号码相同的居民给予另外的号码,名字相同是难免的,没必要改,当然想改也可以
r7.setId("7000");
r8.setId("8000");
r9.setName("sindy");
//发现r4不是不是本辖区的居民,将信息删除
set.remove(r4);
//将更改后的信息输出
System.out.println("经审核,将身份证号相同的问题解决,并为愿意改名的居民改名,重新统计,本辖区共有"+set.size()+"个居民,信息如下:");
Iterator<Resident> it = set.iterator();//返回迭代器
int j=1;
while(it.hasNext())
{
System.out.println("第"+j+"位居民");
System.out.println(it.next());
}
System.out.println("**********************");

//查一下辖区内是否有身份证号为600000,叫做salory的居民
if(set.contains(r6))
{
System.out.println("这位名叫"+r6.getName()+"身份证号为"+r6.getId()+"的居民在本辖区");
}
else
{
System.out.println("本辖区没有这个居民");
}

//查一下辖区内是否有身份证号为1100000,叫做liyang的居民
if(set.contains(r11))
{
System.out.println("这位名叫"+r11.getName()+"身份证号"+r11.getId()+"的居民在本辖区");
}
else
{
System.out.println("本辖区没有这个居民");
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: