【问题标题】:LinkedHashSet Not Removing DuplicatesLinkedHashSet 不删除重复项
【发布时间】:2014-03-27 23:53:52
【问题描述】:

我正在尝试创建一个搜索算法,将坐标对存储在一个名为 HashSquareSpec 的包装类中。为了避免重复并保持插入顺序,我将每个 HashSquareSpec 插入到 LinkedHashSet 中。即使我重写了 equals() 方法和 hashCode() 方法,LinkedHashSet 仍然接受两个 HashSquareSpec 对象 相同的坐标对。

public static void main(String [] args)
{
    LinkedHashSet<HashSquareSpec> firedShots = new HashLinkedSet<HashSquareSpec>();
    HashSquareSpec a = new HashSquareSpec(1,2);
    HashSquareSpec b = new HashSquareSpec(2,2);
    HashSquareSpec c = new HashSquareSpec(1,2);
    HashSquareSpec d = new HashSquareSpec(3,2);

    firedShots.add(a);
    firedShots.add(b);
    firedShots.add(c);
    firedShots.add(d);
    System.out.println(a.equals((SquareSpec)c));
    Iterator l = firedShots.iterator();
    while(l.hasNext())
    {
        System.out.println(l.next().hashCode());
    }
}

Output:
true
38444474
38474265
38444474
38504056

HashSquare 类

public class HashSquareSpec extends SquareSpec 
{
  public HashSquareSpec(int sx, int sy) 
  {
    super(sx,sy);
  }

  public HashSquareSpec(String codeString) 
  {
    super(codeString);
  }

  @Override  
  public int hashCode() 
  {  
    return this.toString().hashCode();  
  }  

  public boolean equals(HashSquareSpec other) 
  {
    if(this.toString().equals(other.toString()))
      return true;
    else
      return false;
  }
}

以及HashSquareSpec的超类

public class SquareSpec {
  public int x;
  public int y;

  public SquareSpec(int sx, int sy) {
      this.x = sx; 
      this.y = sy;
  }

  public SquareSpec(String codeString) {
      this.x = Integer.parseInt(codeString.substring(1,2));
      this.y = Integer.parseInt(codeString.substring(3,4));
  }

  public String toString() {
      return("(" + x + "," + y + ")");
  }

  public boolean equals(SquareSpec other) {
      return (other.x == this.x  && 
              other.y == this.y );
    }
  }

尽管有许多不同的 hashCode 变体以及 Eclipse equals 和 hashCode 生成,但 firedShots 数据结构不断接受重复。我的代码有什么问题?

【问题讨论】:

    标签: java coordinates hashcode no-duplicates linkedhashset


    【解决方案1】:

    您在正确的轨道上,覆盖了hashcodeequals,但您错误地覆盖了HashSquareSpec(和SquareSpec)中的equals method from Object。参数必须是Object。因为它没有被覆盖,所以调用来自Objectequals,它比较对象引用以查看它们是否是同一个对象。他们不是,所以“重复”是允许的。

    试试:

    @Override
    public boolean equals(Object other) 
    {
      if(this.toString().equals(other.toString()))
        return true;
      else
        return false;
    }
    

    您还应该测试other 是否为null,然后确保other 是同一类型。

    包含@Override 注释,这样如果该方法实际上没有覆盖任何内容,编译器就会报错。

    【讨论】:

    • 这也不是一个好的equals 实现;你应该做instanceof 检查。 (例如,您的实现不是对称的,因为这将 equalString。)
    • @LouisWasserman 非常正确,这就是为什么包含一个关于空检查和检查other 是否属于同一类型的句子。
    【解决方案2】:

    它仍在接受,因为您没有覆盖 equals 方法。您需要覆盖boolean equals(Object)。问题是您正在定义一个新方法,例如 boolean equals(SquareSpec)

    这是LinkedHashSet#add(T)最终调用的方法:

    HashMap#put(K, V):

    @Override public V put(K key, V value) {
        if (key == null) {
            return putValueForNullKey(value);
        }
    
        int hash = secondaryHash(key.hashCode());
        HashMapEntry<K, V>[] tab = table;
        int index = hash & (tab.length - 1);
        for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
            if (e.hash == hash && key.equals(e.key)) {
                preModify(e);
                V oldValue = e.value;
                e.value = value;
                return oldValue;
            }
        }
    

    如您所见,它使用hashCodeequals(Object) 进行比较。

    【讨论】:

      猜你喜欢
      • 2014-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-17
      • 2016-08-13
      • 2020-07-21
      • 2021-07-16
      • 2017-05-15
      相关资源
      最近更新 更多