之前对这两个方法感觉很平常,不知道有啥作用,在复习java 容器类的时候我知道其奥秘了。
HashSet 、HashMap如何判断集合元素和map中的key不重复?
由于hashSet内部实现就是HashMap的key,所以分析HashMap就可以了。会先检查对象的HashCode 是否和集合中的已有的重复与否,不同表示不重复,若相同在调用equals 进行比较,true 表示重复,false 不重复。
那就分析HashCode :假如自定义实体类没有重写Object的方法,默认会用Object的方法,而Object的HashCode的比较就是比较对象地址。
equals() : 这个方法是
public boolean equals(Object obj) { return (this == obj); }
也是比较对象是否相等,即地址是否相等。
问题?
自定义对象People
public class People {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public People(String name) {
this.name = name;
}
然后测试:
public static void main(String[] args) {
People people1 = new People("sjh");
People people2 = new People("sjh");
HashSet<People> hashSet = new HashSet<>();
hashSet.add(people1);
hashSet.add(people2);
System.out.println(hashSet.size());
其打印结果为 2
假如HashSet 表示班级,new People 表示学生,那相当于王班级里装了2次同一个人(不考虑同名的学生),遇到这种情况,我们应该重新修改一下People 类?
即重写equals和 hashCode ();加入代码
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof People)) return false;
People people = (People) o;
return Objects.equals(getName(), people.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName());
}
再次运行就会打印 1 。 再次分析,先看hashCode方法,我们针对名称,而不是对象,这样其名称相同,说明不符合装入set的要求。再看equals(),点击HashMap的源码,会发现如下代码
由于(k = p.key) == key比较的是两个对象的地址,所以自然是false,接着就进入key != null && key.equals(k)的判断,而由于Student类中没有equals方法,所以这里调用的是Object类中的equals方法,而通过查找我们发现,Object类中的equals方法比对的仍然是对象的地址,这样返回的结果还是false,那么我们之前所做的努力就白费了,所以当我们重写了People的equal方法后就会按照我们写的来。运行 return Objects.equals(getName(), people.getName()); 会返回true 表示对象相同,这样就装入set失败。
这样就明白了。
参考文章:https://blog.csdn.net/GaoYan__Ze/article/details/81674079
https://blog.csdn.net/mgl934973491/article/details/71169659