HashSet是如何判断新增元素是否重复的?
首先我们要知道HashSet底层的数据结构是哈希表。根据哈希表得出的哈希值代表该对象的储存位置。
HashSet先调用元素对象的hashcode方法,JVM虚拟机来判个对象在物理位置上是否相等,也就是看两个元素的哈希值是否相等,如果不等那肯定是不同对象,就直接添加进set集合。
如果相等,再根据两个元素对象的equals方法判断在业务上是否相等,是否返回true,为ture则被认为是相同对象,不能重复添加,为false则可以添加。
拓展
常用类不用重写,先人已经写好了
自定义类(由于先人不知道这些类的比较规则,所以需要我们去重写)
(1)重写时,重写equals,也应该重写hashcode方法;
(2)在规范上,JVM要求:
- equals方法返回true的两个对象,(两个对象重复了),hashcode也应该是同一个值(一个物理地址);
- 而equals方法返回false的两个对象,hashcode也应该是不同的值;(两个对象没有重复,所以是两个不同的物理地址)
建立一个StudentBean
public class StudentBean {
private String name;
private int grade;
private int age;
}
让hash算法根据内容计算hash
public int hashCode(){
//每个对象的hashcode值是可以重写的。
int code = 0;
char[] nameArray = this.name.toCharArray();
for(int i = 0; i < nameArray.length; i++){
code += nameArray[i];
}
code += age+grade;
return code;
}
防止hash碰撞(地址值不一样,但hash值一样)的情况,重写equals,确保去除问题值
@Override
public boolean equals(Object obj) {//传进来一个stu对象
if(obj ==null){ //对象不为非空
return false;
}
if(this == obj){ //比较两个对象 (地址引用)
return true;
}
if(obj instanceof StudentBean stu){ //同一个类型
if(this.name.equals(stu.name) && this.age == stu.age
&& this.grade==grade){
return true;
}else{
return false;
}
}else{
return false;
}
}
测试1
public static void main(String[] args) {
Set<StudentBean> stuSet = new HashSet<>();
StudentBean stu1= new StudentBean("江小白",18,1);
StudentBean stu2= new StudentBean("江小白",20,2);
stuSet.add(stu1);
stuSet.add(stu2);
}
两个StudentBean对象,hash值不相等,不重复,两个都可以添加进Set集合
测试2
public static void main(String[] args) {
Set<StudentBean> stuSet = new HashSet<>();
StudentBean stu3= new StudentBean("江小白",18,2);
StudentBean stu4= new StudentBean("江小白",19,1);
stuSet.add(stu3);
stuSet.add(stu4);
}
两个StudentBean对象,hash值 相等
继续equals判断,age和grade数据不等,返回false,两者不重复,都可以添加进Set集合
测试3
public static void main(String[] args) {
Set<StudentBean> stuSet = new HashSet<>();
StudentBean stu5= new StudentBean("江小白",18,1);
StudentBean stu6= new StudentBean("江小白",18,1);
stuSet.add(stu5);
stuSet.add(stu6);
}
两个StudentBean对象,hash值相等,且equals比较 返回true,两者重复,stu6无法添加进Set集合