9

我似乎无法让HashSet实例按预期工作。我使用的代码如下:

import testing.Subclass;
import java.util.HashSet;

public class tester {
  public static void main(String[] args) throws Exception {
    HashSet<Subclass> set = new HashSet<Subclass>();
    set.add(new Subclass("007812"));
    set.add(new Subclass("007813"));
    System.out.println("Set size " + set.size());
    set.add(new Subclass("007812"));
    System.out.println("Set size " + set.size());

    for(Subclass sub : set) {
      System.out.println(" sub acctNbr " + sub.getAcctNbr());
    }
  }
}

子类

public class Subclass implements Comparable<Subclass> {

  public Subclass(String acctNbr) {
    this.acctNbr = acctNbr;
  }
  private String acctNbr;
  public String getAcctNbr() {
    return this.acctNbr;
  }
  public int compareTo(Subclass other) {
    return this.getAcctNbr().compareTo(other.getAcctNbr());
  }

  public boolean equals(Subclass other) {
    if(other.getAcctNbr().equals(this.getAcctNbr()))
      return true;
    else
      return false;
  }
  public int hashCode() {
    return acctNbr.hashCode();
  }
}

此代码输出

sross@sross-workstation:~/Documents$ javac testing/Subclass.java
sross@sross-workstation:~/Documents$ javac tester.java
sross@sross-workstation:~/Documents$ java tester
Set size 2
Set size 3
 sub acctNbr 007812
 sub acctNbr 007812
 sub acctNbr 007813
sross@sross-workstation:~/Documents$
4

6 回答 6

22

您需要覆盖equals(Object). 而不是这样做,您已经实现了一个equals带有签名的方法equals(Subclass)。因此,您正在使用为相等性测试定义HashSet的默认equals(Object)方法。Object

默认equals(Object)实现基于对象标识,因此该集合“允许”您添加两个String虽然在语义上相等但不是同一个对象的 s。

于 2009-11-02T20:36:55.957 回答
6

您没有正确覆盖Object.equals().

@Override
public boolean equals(Object other) {
    if ((other == null) || !(other instanceof Subclass)) {
        return false;
    }
    return ((Sublcass) other).getAcctNbr().equals(this.getAcctNbr());
}

该方法boolean equals(Subclass other)创建了第二种方法,这不是您打算做的。

于 2009-11-02T20:37:32.703 回答
3

两个元点:

首先,养成@Override每次你认为你正在覆盖一个方法时使用的习惯。这会导致您的示例代码无法编译,从而导致您发现问题。

其次,如果您使用的是 IDE,并且它没有为您突出显示漂亮的粗体警告,则说明它配置错误!你应该修复它!

而且,如果您不使用 IDE——您真的非常应该使用。一旦你输入public boolean equals(Subclass other),文本会改变颜色,并会显示一个警告,告诉你你可能的问题是什么。

顺便说一句,我所采用的标准成语equals()是这样的:

@Override public boolean equals(Object object) {
  if (object instanceof Subclass) {
    Subclass that = (Subclass) object;
    return this.anInt == that.anInt
        && this.aString.equals(that.aString); // for example
  }
  return false;
}

某些情况下,值得在前面加上一个,if (object == this) { return true; }但养成一个常规的习惯真的不值得。

于 2009-11-04T01:03:02.577 回答
2

我遇到了几乎同样的问题,因为每个人都说你需要覆盖正确的public boolean equals(Object o)方法。但这还不够!

还需要覆盖public int hashCode()(就像您所做的那样),否则,java 根本不会调用该equals方法。

于 2012-09-06T19:21:05.880 回答
0

你的 equals 方法永远不会被调用。的签名equals要求它采用Object,而不是其他一些类(包括碰巧正在实现的任何类equals)。

public boolean equals(Object other) {
    ...
}
于 2009-11-02T20:40:14.757 回答
0

首先猜测,看起来您equals(Subclass other)应该按照您的意愿equals(Object other)覆盖该java.lang.Object.equals()方法。可能该集合正在调用底层equals()实现。

于 2009-11-02T20:38:08.100 回答