插入后更改值后,重复元素被添加到集合中

问题描述 投票:0回答:3

我有一个集合,其中添加了两个不同的对象。插入后,我更改其中一个对象,使两个对象相等(通过对象类中重写的 equals 方法进行验证)。此时,我的集合中有两个重复的元素。现在我尝试将这两个重复的对象添加到一个新集合中,即使 equals 方法为它们返回 true,我仍然能够添加它们。下面是相同的代码。有人可以告诉我我到底错过了什么吗?

public class BasicSetImpl{
public int num; String entry;
public BasicSetImpl(int num, String entry){
  this.num = num;
  this.entry = entry;
}

@Override
public int hashCode() {
  return Objects.hash(entry, num);
}

@Override
public boolean equals(Object obj) {
  BasicSetImpl newObj = (BasicSetImpl)obj;
  if (this.num == newObj.num)
    return true;
  else
    return false; 
}



public static void main(String[] args){
  Set<BasicSetImpl> set = new HashSet<>();
  BasicSetImpl k1 = new BasicSetImpl(1, "One");
  BasicSetImpl k2 = new BasicSetImpl(2, "Two");
  set.add(k1);
  set.add(k2);
  
  k2.num = 1;
  
  System.out.println(k1.equals(k2));  //This line returns True
  
  Set<BasicSetImpl> newSet = new HashSet<>();
  newSet.add(k1);
  newSet.add(k2);
  
  //Set.size here is two
java collections set
3个回答
0
投票

基于哈希的集合,在本例中,

HashSet
使用对象
hashCode
方法来计算哈希值作为对象内容的函数。由于您同时考虑entry和num来确定对象的哈希码值,因此这两个对象具有不同的哈希码,因为它们与entry不同。因此,它们属于两个不同的哈希桶,并且永远不会被识别为相同。

但是,如果您按如下方式设置条目

k2.entry = "One";

那么 k1 和 k2 都有相同的 hashcode 值。那么它们都属于同一个哈希桶,并且根据 equals 方法,两个对象是相同的。因此,现在重复项将被忽略。

但是,这里潜伏着一个问题。理想情况下,相等的对象必须具有相等的哈希码。但是,就你而言,事实并非如此。如果两个对象具有相同的 num 值,则它们相等,但它们可能会产生不同的 hashcode 值。因此,正确的解决方案是按如下方式更改您的 hashCode。

@Override
public int hashCode() {
    return Integer.hashCode(num);
}

现在,如果没有我们通过设置

k2.entry = "One";

添加的 hack,它应该按照您期望的方式运行

0
投票

hashCode
equals
方法必须一致。

来自文档

如果根据 equals(Object) 方法两个对象相等,则对这两个对象调用 hashCode 方法必须产生相同的整数结果。

在你的情况下,尽管它们是相等的,但他们的

hashCode
是不同的。 添加元素时
HashSet
检查添加对象的哈希值,并且仅当集合中存在具有相同哈希值的现有对象时,
HashSet
检查这些具有相同哈希值的对象是否相等。


0
投票

套餐A;

导入java.util.HashSet; 导入 java.util.Objects;

公共班级名称{

public static class Student {

    
    public String getNane() {

        return nane;

    }



    public Student(String nane, int id) {

        this.nane = nane;

        this.id = id;

    }



    public void setNane(String nane) {

        this.nane = nane;

    }



    public int getId() {

        return id;

    }



    public void setId(int id) {

        this.id = id;

    }



    public String nane;

    public int id;

    @Override 
    public String toString()
    {
        return nane + "   " + id;
    }


    @Override

    public boolean equals(Object o) {

        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        return id == student.id;

    }



    @Override

    public int hashCode() {

        return Objects.hash(id);

    }

}

public static void main(String args[])
{
    
    HashSet<Student> studentSet = new HashSet<>();

     

    Student st1 = new Student("Nimit", 1);

    Student st2 = new Student("Rahul", 3);

    Student st3 = new Student("Nimit", 2);


    Student st4 = new Student("Raj", 2);


    studentSet.add(st1);

    studentSet.add(st2);

    studentSet.add(st3);

    studentSet.add(st4);


    System.out.println(studentSet.size());  // 3

    st1.id = 3;
    st1.nane= "Rahul";
    
    System.out.println(studentSet.size()); //      3
    studentSet.add(st1);
    
    studentSet.forEach(System.out::println);
    
    
}

}

答案是:

3 3 拉胡尔 3 尼米特2号 拉胡尔 3

这个集合如何包含2个相同的Student对象(它们通过重写 equal 方法相等)。知道这是怎么回事吗?

© www.soinside.com 2019 - 2024. All rights reserved.