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("本辖区没有这个居民");
}
}
}
相关文章推荐
- jQuery编程的最佳实践
- linux目录详细介绍
- 团队项目:个人工作总结09
- 冲刺07
- 《关于浮点数的各个知识点总结》
- 西电OJ - 1044 炸金花
- C++基本数据类型简便定义
- 课堂作业8
- 工作后准备的书籍
- Oracle修改字段的方法
- php+mysql中文无法检索出数据
- [super performSelector:sel]探秘
- 冲刺第十天
- 基于git的源代码管理模型——git flow
- leetcode26:Remove Duplicates from Sorted Array
- 西电OJ - 1042 另一个简单游戏
- BIOS入门之我见-内存
- `OpenCV2.4.9+Qt5.x+Qt Creator`配置
- setStyleSheet来设定窗口部件的样式(前景色,背景图片)
- PHP整数取余返回负数的相关解决方法