Set 集合无法去重相同内容的父类对象和子类对象的问题解决
Iterator it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
结果为
测试后发现,即使 Student 类里面已经重写了 equals 方法,也没有去重
然后再试试看,写一个一样的 Student 类的对象
package test.GenericDemo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set set = new HashSet();
Student s = new Student("zhang",12);
Student s1 = new Student("zhang",12);
Children c = new Children("zhang",12);
set.add(s);
set.add(s1);
set.add(c);
Iterator it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
结果和上面的一样
说明 equals 方法正常的运作了,但是判断父类对象和子类对象的时候出现了问题
在解决这个问题之前,需要先解释一下,Set 集合去重的原理
具体的源码就不放出来了,简单来说就是首先计算传进来的元素的哈希值,如果传进来的元素为 null,则返回哈希值为 0,如果不是 null,则计算该元素的哈希值。
而 HashSet 集合完成去重操作底层调用的是 HashMap 中的 put()方法,借助了哈希表
根据元素之前计算出来的哈希值,再进行相关运算,得到元素在
哈希表中的存储位置
如果该元素的位置 null,表示该位置没有元素,可以存储,就创建新的结点,存储元素
如果该元素的位置不为 null,则要进行比较
存入的元素和以前该位置的元素的哈希值进行比较
—— 如果哈希值不同,继续向下执行,把元素添加集合中
—— 如果哈希值一样,会调用对象的 equals()方法进行比较
————如果比较 equals()方法返回的是 false,会继续向下执行,然后将元素插入到集合中
————如果比较 equals()方法返回的是 true,说明元素的哈希值和内容都一样,表示元素重复了
所以知道了原理后,再回过头来,去查看父类对象和子类对象的哈希值
package test.GenericDemo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set set = new HashSet();
Student s = new Student("zhang",12);
Student s1 = new Student("zhang",12);
Children c = new Children("zhang",12);
//查看对象的哈希值
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
System.out.println(c.hashCode());
//比较对象之间的值
System.out.println(s.equals(s1));
System.out.println(s.equals(c));
}
}
这里发现,这些对象的哈希值相同,但是 equals 方法判断出父类对象和子类对象不同
因此才导致,子类对象被加入进了 Set 集合当中
那么现在,来看看 Student 类的 equals 方法
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
可以看到,这一条判断语句 if (o == null || getClass() != o.getClass()) return false;
再回过头去,看一看两个对象调用 getClass()后的结果
package test.GenericDemo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set set = new HashSet();
Student s = new Student("zhang",12);
Student s1 = new Student("zhang",12);
Children c = new Children("zhang",12);
System.out.println(s.getClass());
System.out.println(c.getClass());
}
}
结果为
好了,到此终于知道为什么 equals 方法,会认为明明属性值都相同的父类对象和子类对象是不一样的了
那么,最后就是修改措施,将 equals 方法改为
public boolean equals(Object o) {
if (this == o) return true;
if(o instanceof Student){
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
评论