【问题标题】:Duplicate elements being added in a set after I change the value after insertion插入后更改值后将重复元素添加到集合中
【发布时间】:2021-05-12 09:14:40
【问题描述】:

我有一个集合,其中添加了两个不同的对象。插入后,我以两个对象相等的方式更改其中一个对象(由对象类中覆盖的 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

【问题讨论】:

  • 如果两个对象相等(根据equals 方法),那么两个对象必须从它们的hashCode 方法返回相同的值。在您的代码中并非如此。参考stackoverflow.com/questions/2265503/…

标签: java collections set


【解决方案1】:

基于散列的集合,在这种情况下HashSet 使用对象hashCode 方法来计算散列值作为对象内容的函数。由于您同时考虑了 entry 和 num 来确定对象的 hashcode 值,因此这两个对象具有不同的 hashcode,因为它们与 entry 不同。因此它们属于两个不同的哈希桶,永远不会被识别为相同的。

但是,如果您将条目设置如下

k2.entry = "One";

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

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

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

现在,如果没有我们通过设置 k2.entry = "One"; 添加的 hack,它应该会按照您预期的方式运行

【讨论】:

    【解决方案2】:

    hashCodeequals 方法必须一致。

    来自documentation

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

    在您的情况下,尽管它们相等,但它们的 hashCodes 却不同。 添加元素时HashSet检查添加对象的哈希值,并且仅当集合中存在具有相同哈希值的对象时,HashSet检查这些具有相同哈希值的对象是否相等。

    【讨论】:

      猜你喜欢
      • 2020-06-17
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多