在说HashSet集合怎么存储自定义对象细节之前,先看看HashSet类的特点吧。
通过查阅API,发现HashSet集合:
1、 HashSet集合底层使用哈希表结构
2、 HashSet集合中的存储的元素是无序的
3、 因为继承了Set接口,所以不能存储重复元素
4、 允许存储null元素,但是只能有一个
5、 性能:查询元素和存储不重复元素的效率比较高
既然,HashSet集合底层使用哈希表,再来说说哈希表是什么个东西吧?
2. 哈希表
集合的底层使用哈希表。
所谓的哈希表其实底层还是使用数组,只是这个数组中存在一种算法:哈希算法。所以才称为哈希表(下图参考传智播客唐文杰老师)
HashSet集合底层哈希表存储元素的过程:
1、 在向HashSet集合中存储元素时,会先拿要存储的元素和哈希算法结合,计算出哈希值(元素的存储位置)。
2、 判断计算出的存储位置上是否已经有元素存在了
有元素存在:拿要存储的元素和已经存在的元素进行equals比较
equasl结果:相同 ,表示重复元素。不做存储操作
equals结果:不相同, 继续计算新的存储位置(常用作法:拉链法)
拉链法:会使用当前存储位置和哈希算法继续计算新的存储位置,再判断新的存储位置上是否有元素存在(和之前方案类同)
没元素存在:直接把元素存到该位置上思考:集合中只能存储什么类型的元素? 引用类型
思考:引用类型的元素有父类吗? 最高父类是Object
对,你猜对了。在object 类中存在一个功能,可以用来计算哈希值
好了,说了那么多关于哈希表底层的内容,我们再言归正题,笔者通过一个案例来说明怎么才能存储自定义对象不重复呢?package com.hmtest.demo;
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
public class HashSetTest {
public static void main(String[] args) {
// 创建HashSet集合对象
HashSet set = new HashSet();
//向集合中添加Person对象
set.add(new Person("马云",53));
set.add(new Person("刘强东",43));
set.add(new Person("李彦宏",40));
set.add(new Person("马化腾",41));
set.add(new Person("马化腾",41));
//遍历
for (Iterator it = set.iterator(); it.hasNext();) {
Person p = (Person) it.next();
//输出Person
System.out.println(p);
}
}
}
为什么以在程序执行后,还会出现重复的对象呢?
这是因为在向集合中存储元素时,拿Person对象和哈希算法结合计算出哈希值。而创建的Person对象不同,所以在和哈希算法计算时,也就产生不同的哈希值(没有调用equals方法判断是否相等)。
解决方案:1,让存储的元素使用同一个哈希值,就会调用equals方法比较
具体做法是:在Person类中重写Object类中的hashCode方法,添加如下代码:
public int hashCode(){
return 10;//全部返回相同的哈希值
}
2,在计算出相同的哈希值后,还会存在equals比较对象,产生对象不相同结果。所以还需要在Person中重写Object类中的equals方法。
具体做法如下:在Person类中重写Object类中equals方法(比较对象中的内容)
public boolean equals(Object obj){
//判断你是否为Person对象
if(!(obj instanceof Person)) throw new RuntimeException("类型不匹配!");
Person p = (Person) obj; //强制类型转换
return this.age = p.age&&this.name.equals(p.name);
}
也许你看到上面步骤会抓狂,请不要激动,eclipse会懂你的。。你只需要按照下面的方法,eclipse会为你自动生成
Shift+Alt+S>>>>选择Gerate hasCode()and equals()系统会自动帮你生成所需要重写的代码。