项目场景:
今天在项目中向利用hashset给自定义实体类进行去重,但是去重未成功, 项目中加的@Data注解现在依然未解决,看网上文章有感,so写下了此文章,文章有不足之处,希望各位大佬指正
问题描述
伪代码
/**
* 自定义实体类
* @Description:
* @Date Created in 2022-10-11-20:05
* @Modified By:
*/
public class Stu {
private String name;
private Integer age;
public Stu(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Stu{");
sb.append("name='").append(name).append('\'');
sb.append(", age=").append(age);
sb.append('}');
return sb.toString();
}
}
/**
* 测试类
* @Description:
* @Date Created in 2022-10-11-20:06
* @Modified By:
*/
public class StuTest {
public static void main(String[] args) {
Stu s1 = new Stu("大大王", 100);
Stu s2 = new Stu("大大王", 100);
Stu s3 = new Stu("大大王11", 3);
HashSet<Stu> students = new HashSet<>();
students.add(s1);
students.add(s2);
students.add(s3);
System.out.println(students);
}
}
输出结果:
原因分析:
HashSet 的 add方法使用的是 hashcode 和equals进行比较
需要重写hashcode 和equals
public class Stu {
private String name;
private Integer age;
public Stu(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Stu{");
sb.append("name='").append(name).append('\'');
sb.append(", age=").append(age);
sb.append('}');
return sb.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Stu stu = (Stu) o;
return Objects.equals(name, stu.name) && Objects.equals(age, stu.age);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
/**
* @Description:
* @Date Created in 2022-10-11-20:06
* @Modified By:
*
* 使用HashSet存储自定义对象并遍历
* 通过查看源码发现:
* HashSet的add()方法,首先会使用当前集合中的每一个元素和新添加的元素进行hash值比较,
* 如果hash值不一样,则直接添加新的元素
* 如果hash值一样,比较地址值或者使用equals方法进行比较
* 比较结果一样,则认为是重复不添加
* 所有的比较结果都不一样则添加
*/
public class StuTest {
public static void main(String[] args) {
Stu s1 = new Stu("大大王", 100);
Stu s2 = new Stu("大大王", 100);
Stu s3 = new Stu("大大王11", 3);
HashSet<Stu> students = new HashSet<>();
students.add(s1);
students.add(s2);
students.add(s3);
System.out.println(students);
}
}
重写hashcode 和equals,再次进行测试
去重成功
10月23日补充
向set中添加完对象后,在修改对象,未进行去重 ,不知是什么原因????
欢迎各位大佬指正
直接上代码
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("zhengsan", 12));
students.add(new Student("lisi", 15));
students.add(new Student("wangwu", 20));
HashSet<Student> studentHashSet = new HashSet<>();
for (Student student : students) {
for (int i = 0; i < 2; i++) {
studentHashSet.add(student);
student.setName("张三");
}
}
for (Student s : studentHashSet) {
System.out.println(s);
}
输出结果
将数据放入list中,比较hashcode和equal看它是否相同
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("zhengsan", 12));
students.add(new Student("lisi", 15));
students.add(new Student("wangwu", 20));
HashSet<Student> studentHashSet = new HashSet<>();
for (Student student : students) {
for (int i = 0; i < 2; i++) {
studentHashSet.add(student);
student.setName("张三");
}
}
ArrayList<Student> list = new ArrayList<>();
for (Student s : studentHashSet) {
System.out.println(System.identityHashCode(s) + "," + s);
list.add(s);
}
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(0) + " " + list.get(4));
System.out.println("hashcode:" + (list.get(0) == (list.get(4))));
System.out.println("equal:" + list.get(0).equals(list.get(4)));
}
hashcode和equal是相同的,但是没有去重,很是头大。
23年5月25日 破案啦
将上面的代码改变一下,调整一下setName的位置,并打印hashcode
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("zhengsan", 12));
students.add(new Student("lisi", 15));
students.add(new Student("wangwu", 20));
HashSet<Student> studentHashSet = new HashSet<>();
for (Student student : students) {
for (int i = 0; i < 2; i++) {
System.out.println(student.hashCode());
studentHashSet.add(student);
student.setName("张三");
}
}
for (Student s : studentHashSet) {
//System.out.println(s + "hashcode="+ s.hashCode());
System.out.println(s);
}
输出结果:
-1318086619
776222
3323429
776315
-795135410
776470
Student{name='张三', age=15}
Student{name='张三', age=12}
Student{name='张三', age=20}
Student{name='张三', age=15}
Student{name='张三', age=12}
Student{name='张三', age=20}
Process finished with exit code 0
可以看到向set集合中添加的元素的hashcode都是不一样的,set集合是根据hashcode和equal的值是否相同进行去重的,hashcode不一样,当然不可以去重。
继续改变一下setName的位置,看一下效果
ArrayList<Student> students = new ArrayList<>();
students.add(new Student("zhengsan", 12));
students.add(new Student("lisi", 15));
students.add(new Student("wangwu", 20));
HashSet<Student> studentHashSet = new HashSet<>();
for (Student student : students) {
for (int i = 0; i < 2; i++) {
student.setName("张三");
System.out.println(student.hashCode());
studentHashSet.add(student);
}
}
for (Student s : studentHashSet) {
//System.out.println(s + "hashcode="+ s.hashCode());
System.out.println(s);
}
输出结果
776222
776222
776315
776315
776470
776470
Student{name='张三', age=15}
Student{name='张三', age=12}
Student{name='张三', age=20}
可见已经去重了,hashcode值也一样
无法去重的原因:
其实很简单,第一次向set集合中存储数据,第二次使用setName改变了Student对象的值,所以当然不能去重。 使用双重循环,添加数据的时候一定要注意这个问题!!!
完结