黑马程序员_集合学习之hashset学习笔记
------- android培训、java培训、期待与您交流! ----------
在collection中,除了list派系之外,还有一个set派系
Set中元素是无序的,也就是存入和取出顺序不一定一致,而且元素不能重复。
更确切地讲,set 不包含满足 e1.equals(e2)
的元素对 e1
和 e2
,并且最多包含一个 null 元素
查看set接口的功能,才发现set和collection是一致的。
在set接口下,有两个我们常用的类比较重要
HashSet:它的底层数据结构式哈希表
TreeSet
什么叫做哈希表?
比如,我们定义了两个Demo对象
class Demo
{
}
Demo d1 = new Demo();
Demod2 = new Demo();
System.out.println(d1);//输出day1.Demo@150bd4d
System.out.println(d2);//输出day1.Demo@1bc4459
这是定义了一个哈希结构的集合。将上述两个对象的哈希值存入到集合中
150bd4d,1bc4459
注意,存放的顺序不是按照你存入的数据去定义的。这也就是和arraylist的区别
顺序是按照哈希值的顺序去存入的。
在我们去取的时候,是按照表里边的顺序去取。
经过我的测试,在其类中加入了
class Demo
{
publicinthashCode()
{
System.out.println("1");
return 0;
}
}
已验证是否在进入集合中时候,调用了自身的hashCode()方法。
Demo d1 = new Demo();
Demod2 = new Demo();
HashSet<Demo> hs = newHashSet<Demo>();
hs.add(d1);
hs.add(d2);
输出了
1
1
故以上得以证明确实调用了对象的hashcode方法。
切记,哈希表是按照哈希值来存储的。当哈希值一样的时候,
还有一次校验的方式。就是使用看是否是同一个对象。也就是调用对象的equals
方法。 如果equals不等的话,就会在该hashcode对应的地址顺延
如两个hashcode都为1,但是equals不同
则 1(同一地址,这里存放一个对象)------1(另一个对象),也就是
如果hashcode的值不一样,那么没有必要计较equals方法了
这里突然想到了equals和==的区别,
==比较的是两个对象的内存地址是否一致。
Demo d1 = newDemo();
Demo d2 = new Demo();
则d1==d2为false
Demo d1 = newDemo();
Demo d2 = d1;
则d1==d2为true
当使用equals方法时候,如果对象实现了equals方法,则使用其自己的。
如果没有实现,则调用从object中得到的。
publicbooleanequals(Object obj){
return (this ==obj);
}
其实也就是比较的内存地址了。
也就是如果你没有实现equals方法,则==和equals得到的值一样。
其实hashset就是hash表结构的。。。
HashSet<String>hs = new HashSet<String>();
hs.add("java01");
hs.add("java02");
hs.add("java03");
hs.add("java03");
for(Strings:hs)
{
System.out.println(s);
}
java02
java03
java01
这里我们验证了不可重复和无序的规律
这里我们来说往hashSet集合中存入自定义对象。
classPersonDemo
{
privateStringname;
publicPersonDemo(String name,int age) {
super();
this.name =name;
this.age =age;
}
privateintage;
publicString getName() {
returnname;
}
publicvoidsetName(String name) {
this.name =name;
}
publicintgetAge() {
returnage;
}
publicvoidsetAge(int age) {
this.age =age;
}
publicinthashCode()
{
System.out.println("code");
returnname.hashCode()+age;
}
publicboolean equals(Objecto)
{
System.out.println(“equals”);
PersonDemo p = (PersonDemo)o;
returnname.equals(p.name)&&age==p.age;
}
}
上边我们定义了一个对象并实现了equals和hashCode(根据具体的比较形式)。
并创建
HashSet<PersonDemo>hs = new HashSet<PersonDemo>();
hs.add(newPersonDemo("dabin",11));
hs.add(newPersonDemo("dabin1",12));
hs.add(newPersonDemo("dabin2",13));
hs.add(newPersonDemo("dabin2",13));
控制台输出
hashcode
hashcode
hashcode
hashcode
equals
原理如下。
Dabin对象调用hashcode的到一个哈希吗。放到内存中
Dabin1对象调用hashcode的到一个哈希吗。与dabin比较,hashcode不同,放到内存中。
Dabin2对象调用hashcode的到一个哈希吗。与dabin1和2比较,hashcode不同,放到内存中。
当再次存入dabin2的时候,由于hashcode码一样,故调用了equals方法。
Dabin(码)
Dabin1(码)
Dabin2(码)
由于equals方法一致,所以。Dabin2没有被放入。
综上,hashset是通过hashcode和euqals保证元素的一致性。
当说完增加元素的时候,我们说一说删除和寻找元素的原理
HashSet<PersonDemo>hs = new HashSet<PersonDemo>();
hs.add(newPersonDemo("dabin",11));
hs.add(newPersonDemo("dabin1",12));
System.out.println(hs.contains(newPersonDemo("dabin1",12)));
输出为
hashcode.....dabin
hashcode.....dabin1
hashcode.....dabin1//得到了要寻找的hash值,比较后,存在一个hashcode一致的对象,则调用equals做进一步判断
equals//也一致。
True//所以发现元素包含。
Remove也是同样的比较方式。。。
但是对于arraylist来说,只是去比较equals方法,与hashcode无关。