set集合没有索引值,不能重复,底层是map。
当新增元素时,会先调用hashCode()方法,计算对象的哈希值,然后用哈希值%数组长度,算出新增元素的索引值位置;若该索引值位置没有元素,就直接新增,
若该索引值位置有元素,则调用equals()方法,判断两个元素是否重复;若重复,不新增,若不重复,则新增。
具体看代码实现:
//情况一:
这里Set集合的泛型是 String,这是JDK自带的类,按住‘ctrl’键,点击String,查看源码:发现它覆盖重写了Object类的hashCode() 和 equals()方法,所以会自动调用方法进行判断去重。
测试类:添加几条数据,看看输出结果
import java.util.HashSet;
import java.util.Set;
public class Test01 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("张三");
set.add("李四");
set.add("王五");
set.add("张三");
System.out.println(set.size());
System.out.println(set);
}
}
输出结果为:
3
[李四, 张三, 王五]
//情况二:
接下来,我们给Set集合自定义泛型,看看啥情况:
自定义一个Student类,提供基本的get,set方法,无参构造和有参构造,toString()方法
然后再新建set集合,添加几个学生对象,打印看看结果
package HashSet去重原理;
import java.util.HashSet;
import java.util.Set;
public class Test02 {
public static void main(String[] args) {
//自定义泛型:Student
Set<Student> set = new HashSet<>();
set.add(new Student("张三", 22, 1000));
set.add(new Student("李四", 33, 2000));
set.add(new Student("王五", 44, 3000));
set.add(new Student("张三", 22, 1000));
System.out.println(set.size());
for (Student stu : set) {
System.out.println(stu);
}
}
}
class Student{
private String name;
private int age;
private int money;
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", money=" + money + "]";
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age, int money) {
super();
this.name = name;
this.age = age;
this.money = money;
}
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;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
控制台输出结果为:
4
Student [name=王五, age=44, money=3000]
Student [name=张三, age=22, money=1000]
Student [name=李四, age=33, money=2000]
Student [name=张三, age=22, money=1000]
这里自定义的Student类,因为没有重写Object类的hashCode() 和 equals()方法,所以不会进行去重判断
//情况三:
这次我们在 情况二 的基础上,给student类,加上hashCode() 和 equals()方法,并给里面加上一个输出语句,看看结果
( 快捷键:alt+shift+s )
package HashSet去重原理;
import java.util.HashSet;
import java.util.Set;
public class Test02 {
public static void main(String[] args) {
//自定义泛型:Student
Set<Student> set = new HashSet<>();
set.add(new Student("张三", 22, 1000));
set.add(new Student("李四", 33, 2000));
set.add(new Student("王五", 44, 3000));
set.add(new Student("张三", 22, 1000));
System.out.println(set.size());
for (Student stu : set) {
System.out.println(stu);
}
}
}
class Student{
private String name;
private int age;
private int money;
@Override
public int hashCode() {
System.out.println("执行了 hashCode方法,判断索引值位置 有没有元素"); //
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + money;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println("执行了 equals方法,判断 新旧元素 是否重复"); //
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (money != other.money)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", money=" + money + "]";
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age, int money) {
super();
this.name = name;
this.age = age;
this.money = money;
}
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;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
输出结果为:
执行了 hashCode方法,判断索引值位置 有没有元素
执行了 hashCode方法,判断索引值位置 有没有元素
执行了 hashCode方法,判断索引值位置 有没有元素
执行了 hashCode方法,判断索引值位置 有没有元素
执行了 equals方法,判断 新旧元素 是否重复
3
Student [name=李四, age=33, money=2000]
Student [name=张三, age=22, money=1000]
Student [name=王五, age=44, money=3000]
我们发现:这里调用了4次hashCode()方法,因为新增了四个元素,所以判断了4次;
只调用了一次equals()方法,因为新增元素里面,第一个和第四个重复了,所以只调用一次。
总结:Set集合添加元素时:
① 如果泛型是JKD提供的类,只需要提供基本的get,set方法,无参构造,有参构造,toString()方法 ,即可实现去重
② 如果泛型是自定义的类,必须加上 hashCode() 和 equals()方法,才能实现去重