黑马程序员:Java基础——Set集合之HashSet,javahashset
黑马程序员:Java基础——Set集合之HashSet,javahashset
1.HashSet概念
|--Set:元素师无序的,元素不可以重复,该集合无索引。 |--HashSet:底层数据结构是哈希表。class Demo{}
class HashSetDemo{
public static void main(String [] args){
Demo d1 = new Demo();
Demo d2 = new Demo();
sop(d1);
sop(d2);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
输出的即为d1和d2的内存地址,也就是哈希值。
下图是HashSet存储机制:
接下来,我们试用一下HashSet,通过查看API文档,我们看到没有任何独特的或是新的没有接触过的方法,所以我们按老方法,新建一个HashSet并将其遍历出来:
public static void sop(Object obj){
System.out.println(obj);
}
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add("Java01");
hs.add("Java02");
hs.add("Java03");
hs.add("Java04");
for(Iterator it = hs.iterator();it.hasNext();){
sop(it.next());
}
}
运行结果则是:
Java02
Java03
Java04
Java01
可以看到,不是按我们原有的顺序储存的。
2.HashSet存储自定义对象
我们还以例子说明:将自定义对象作为元素存到HashSet集合中,并去除重复元素。
例如:存人对象,同姓名同年龄视为同一人,为重复元素。依照ArrayList集合的思想,我们写出了一下代码:
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("ZhangSan",21));
hs.add(new Person("LiSi",22));
hs.add(new Person("WangWu",23));
hs.add(new Person("LiSi",22));
for(Iterator it = hs.iterator();it.hasNext();){
Person p = (Person) it.next();
sop("Name:"+p.getsName()+",Age:"+p.getiAge());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
class Person{
private String sName;
private int iAge;
Person(){}
Person(String sName,int iAge){
this.sName = sName;
this.iAge = iAge;
}
public boolean equals(Object obj){
if(!(obj instanceof Person)){
return false;
}else{
Person p = (Person) obj;
System.out.println("this.sName="+this.sName+"--p.sName="+p.sName);
return this.sName.equals(p.sName)&&this.iAge==p.iAge;
}
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public int getiAge() {
return iAge;
}
public void setiAge(int iAge) {
this.iAge = iAge;
}
}
但是,运行结果很不乐观:
Name:WangWu,Age:23
Name:ZhangSan,Age:21
Name:LiSi,Age:22
Name:LiSi,Age:22
我们看到我们的equals方法并没有被调用,这是为什么呢?
因为,我们添加的元素都是new出来的,所带的Hash值都是不一样的,地址不一样,HashSet便认为它们是不一样的。
那么,我们需要重写Object的hashCode()方法。
public int hashCode(){
return 60;
}
当我们运行的时候发现,重复的去掉了,equals方法也被调用了。以下是运行结果
this.sName=LiSi--p.sName=ZhangSan
this.sName=WangWu--p.sName=ZhangSan
this.sName=WangWu--p.sName=LiSi
this.sName=LiSi--p.sName=ZhangSan
this.sName=LiSi--p.sName=LiSi
Name:ZhangSan,Age:21去
Name:LiSi,Age:22
Name:WangWu,Age:23
在Set集合中,重复元素就无法被存进来。这时,我们去掉了重复的,可是,这样每存一个就判断一次,效率是比较低的。
我们不妨用元素的内容,比如:Person的姓名+年龄得到的值作为Hash值,如果不一样,再进行equals判断。
public int hashCode(){
System.out.println(this.sName+"...hashCode"+sName.hashCode());
return sName.hashCode()+iAge;
}
我们编译运行来看看结果:
ZhangSan...hashCode-1367991180
LiSi...hashCode2367699
WangWu...hashCode-1711270815
LiSi...hashCode2367699
this.sName=LiSi--p.sName=LiSi
Name:WangWu,Age:23
Name:LiSi,Age:22
Name:ZhangSan,Age:21
我们发现,当后面LiSi的HashCode值和前面LiSi的HashCode值相同时去判断比较。确认重复,就没有被存入集合中。
然而,即便是这样也会出现漏洞,例如l+21正好与Z+15的HasCode值相同,就会出现重复比较的现象,针对这个,我们在iAge乘以一个随机的数。
return sName.hashCode()+iAge*2;
运行一次,看看结果:
ZhangSan...hashCode-1367991180
LiSi...hashCode2367699
WangWu...hashCode-1711270815
LiSi...hashCode2367699
this.sName=LiSi--p.sName=LiSi
Name:ZhangSan,Age:21
Name:LiSi,Age:22
Name:WangWu,Age:23
以下是修正完的全部代码:
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("ZhangSan",21));
hs.add(new Person("LiSi",22));
hs.add(new Person("WangWu",23));
hs.add(new Person("LiSi",22));
for(Iterator it = hs.iterator();it.hasNext();){
Person p = (Person) it.next();
sop("Name:"+p.getsName()+",Age:"+p.getiAge());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
class Person{
private String sName;
private int iAge;
Person(){}
Person(String sName,int iAge){
this.sName = sName;
this.iAge = iAge;
}
public int hashCode(){
//System.out.println(this.sName+"...hashCode"+sName.hashCode());
return sName.hashCode()+iAge*2;
}
public boolean equals(Object obj){
if(!(obj instanceof Person)){
return false;
}else{
Person p = (Person) obj;
//System.out.println("this.sName="+this.sName+"--p.sName="+p.sName);
return this.sName.equals(p.sName)&&this.iAge==p.iAge;
}
}
最后,我们来总结一下:
HashSet是如何保证元素唯一性呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的HashCode志不同,不会调用equals。
3.HashSet判断和删除的依据
基于上一节练习,我们来对元素来进行删除,为了便于观看,我的代码如下:
System.out.print("判断“ZhangSan,21”是否存在-----");
if(hs.contains(new Person("ZhangSan",21))){
sop("存在");
}else{
sop("不存在");
}
运行结果为:
判断“ZhangSan,21”是否存在-----存在
我们把上节注释掉的打印取消掉,运行结果如下:
ZhangSan...hashCode-1367991180
LiSi...hashCode2367699
WangWu...hashCode-1711270815
判断“ZhangSan,21”是否存在-----ZhangSan...hashCode-1367991180
this.sName=ZhangSan--p.sName=ZhangSan
存在
Name:ZhangSan,Age:21
Name:LiSi,Age:22
Name:WangWu,Age:23
我们发现程序拿到了ZhangSan这个对象,拿去和集合中的元素作对比,结果是存在的,于是输出存在。
我们再来试一试删除数据,将刚刚的判断代码注释掉。
这是删除元素的代码:
hs.remove(new Person("LiSi",22));
我们来运行看看:
ZhangSan...hashCode-1367991180
LiSi...hashCode2367699
WangWu...hashCode-1711270815
LiSi...hashCode2367699
this.sName=LiSi--p.sName=LiSi
Name:ZhangSan,Age:21
Name:WangWu,Age:23
我们发现,LiSi,22这个元素被我们删除掉了。 通过总结,我们发现对于判断元素是否存在,以及删除等操作依赖的方法也是元素的hashCode和equals方法。
以下是全部代码:
import java.util.HashSet;
import java.util.Iterator;
public class HashSetTest {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("ZhangSan",21));
hs.add(new Person("LiSi",22));
hs.add(new Person("WangWu",23));
//hs.add(new Person("LiSi",22));
/*System.out.print("判断“ZhangSan,21”是否存在-----");
if(hs.contains(new Person("ZhangSan",21))){
sop("存在");
}else{
sop("不存在");
}*/
hs.remove(new Person("LiSi",22));
for(Iterator it = hs.iterator();it.hasNext();){
Person p = (Person) it.next();
sop("Name:"+p.getsName()+",Age:"+p.getiAge());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
class Person{
private String sName;
private int iAge;
Person(){}
Person(String sName,int iAge){
this.sName = sName;
this.iAge = iAge;
}
public int hashCode(){
System.out.println(this.sName+"...hashCode"+sName.hashCode());
return sName.hashCode()+iAge*2;
}
public boolean equals(Object obj){
if(!(obj instanceof Person)){
return false;
}else{
Person p = (Person) obj;
System.out.println("this.sName="+this.sName+"--p.sName="+p.sName);
return this.sName.equals(p.sName)&&this.iAge==p.iAge;
}
}
public String getsName() {
return sName;
}
public void setsName(String sName) {
this.sName = sName;
}
public int getiAge() {
return iAge;
}
public void setiAge(int iAge) {
this.iAge = iAge;
}
}
相关文章
- 暂无相关文章
用户点评