HashSet在存储基本类型(包括String)对象时所表现的不重复性
首先我们知道Set集合用于存储用于存储无序,且不能重复的数据。HashSet作为Set集合的实现类,同样具备了这样的特征。有如下实例:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class TestHashSet {
public static void main(String[] args) {
Set set=new HashSet();
set.add("大国");
set.add("大国");
set.add("大大国");
set.add("大国");
set.add("小小国");
//重复的会被覆盖
System.out.println(set.size());
//遍历每一个元素
for(Object o:set) {
System.out.println(o);
}
}
控制台输出结果如下:
可见HashSet中自动进行了覆盖相同内容的元素。其根本原因在于底层中调用了String对Object中重写过的equals方法(比较两个字符串对象内容是否相同),而Object中equals方法是比较两个对象的地址是否相同,Object是所有类的父类,因此所有类都会继承Object中的equals方法。
自定义类对象不重复性如何保证
我们在自定义类时往往会设定一系列属性,并且认为所有属性均相同的两个对象是一个对象。例如自定义People类(类对象具有编号和名字两个属性)。那么问题来了,每new一个新People对象都会在堆中开辟一个新地址,即使属性完全相同却拥有不同的地址:
public class TestHashSet2 {
public static void main(String[] args) {
Set set=new HashSet();
People p1=new People(1001,"大国");
People p2=p1;
People p3=new People(1001,"大国");
set.add(p1);
set.add(p2);
set.add(p3); //推测Set判断对象是否重复的依据,是否是两个内存
System.out.println(set.size());
set.forEach(System.out::println);
}
}
这时如果想要保证存储对象“不重复”就需要在People类中再次对Object中equals方法以及hashCode方法同时进行重写:
@Override
public int hashCode() {
return this.getId();//直接将编号代替HashCode值
}
public boolean equals(Object obj) {
if(obj==this) {
return true;
}
if(obj instanceof People){
People p=(People)obj;
if(this.getName().equals(p.getName())) {//注释处
return true;
}
}else {
return false;
}
return false;
}
注释处需要注意的是这里的equals方法不是People重写的equals方法在进行递归操作,而是字符串.equals(),因此是String中的equals方法的调用。
经过对hashCode以及equals方法同时重写,我们满足了属性相同即视为相同对象的需求。