Set集合不重复原理
1.关于set集合
- 特点:set集合没有索引,没有顺序,元素不能重复
- 所属包:java.util
- 常用实现类:HashSet、LinkedHashSet、TreeSet
2.演示
import java.util.HashSet;
import java.util.Set;
public class SetTest1 {
public static void main(String[] args) {
// 创建Set对象
Set<String> set = new HashSet<>();
// 添加5个String类型元素
set.add("zhangsan");
set.add("lisi");
set.add("zhangsan");// 第3个元素和第1个元素重复
set.add("wangwu");
set.add("zhaoliu");
// 输出Set对象
System.out.println(set + "\tsize=" + set.size());
}
}
输出结果为:
[lisi, zhaoliu, zhangsan, wangwu] size=4
根据结果可以看出:set集合去重了元素“zhangsan”
3.底层原理
hash结构在HashSet中是用数组+链表实现的
去重操作发生在新增过程中:
1. 使用新增元素的hashCode()方法计算其哈希值
2. 用哈希值%数组长度,计算出新增元素的索引值位置
2.1 如果数组该位置为null:则直接添加
2.2 如果数组该位置有元素:使用equals()方法判断对应链表元素是否重复
2.2.1 重复:不新增(不重复的原因)
2.2.2 不重复:新增,挂到链表的最后位置
判断是否重复的标准:两个元素的哈希值相同 && (地址值相同 || equals相同)
4.常见问题及解决办法
使用自定义类型对象作为元素
import java.util.HashSet;
import java.util.Set;
//测试类
public class SetTest1 {
public static void main(String[] args) {
// 创建Set对象
Set<Person> set = new HashSet<>();
// 添加5个String类型元素
set.add(new Person("zhangsan", 18));
set.add(new Person("zhangsan", 19));
set.add(new Person("lisi", 20));
set.add(new Person("lisi", 20));// 第4个元素和第3个元素重复
set.add(new Person("lisi", 25));
set.add(new Person("wangwu", 17));
// 输出Set对象
for (Person p : set) {
System.out.println(p);
}
System.out.println("size=" + set.size());
}
}
//自定义类
class Person {
// 成员属性
private String name;
private int age;
// 无参构造
public Person() {
}
// 有参构造
public Person(String name, int age) {
super();
this.name = name;
this.age = 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 "[name=" + name + ", age=" + age + "]";
}
}
输出结果为:
[name=lisi, age=20]
[name=lisi, age=25]
[name=wangwu, age=17]
[name=zhangsan, age=18]
[name=zhangsan, age=19]
[name=lisi, age=20]
size=6
根据结果可以看出:set集合并未去重了元素[name=lisi, age=20]
-
原因
自定义类型的对象使用了Object类的hashCode()方法和equals()方法
-
解决办法
在自定义类中重写hashCode()方法和equals()方法
@Override
public int hashCode() {
return Objects.hash(age, name);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
return age == other.age && Objects.equals(name, other.name);
}
输出结果:
[name=lisi, age=20]
[name=lisi, age=25]
[name=wangwu, age=17]
[name=zhangsan, age=19]
[name=zhangsan, age=18]
size=5