写点什么

Set 集合无法去重相同内容的父类对象和子类对象的问题解决

用户头像
极客good
关注
发布于: 刚刚

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()方法,借助了哈希表


根据元素之前计算出来的哈希值,再进行相关运算,得到元素在


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


哈希表中的存储位置


如果该元素的位置 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);

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Set集合无法去重相同内容的父类对象和子类对象的问题解决