简体   繁体   English

HashSet允许重复

[英]HashSet allows duplicates

I can't seem to get a HashSet instance to work as expected. 我似乎无法使HashSet实例正常工作。 The code I used is as follows: 我使用的代码如下:

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());
    }
  }
}

Subclass 子类

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();
  }
}

This code outputs 该代码输出

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$

You need to override equals(Object) . 您需要重写equals(Object) Instead of doing this you've implemented an equals method with signature equals(Subclass) . 而不是这样做,您实现了带有签名equals(Subclass)equals方法。 Consequently your HashSet is using the default equals(Object) method defined on Object for equality testing. 因此你HashSet使用的是默认equals(Object)方法定义Object平等的测试。

The default equals(Object) implementation is based on object identity, and hence the set "allows" you to add two String s that, whilst semantically equal, are not the same object. 默认的equals(Object)实现基于对象标识,因此该集合“允许”您添加两个String ,这些语义在语义上均相等,但不是同一对象。

You did not correctly override Object.equals() . 您没有正确重写Object.equals()

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

The method boolean equals(Subclass other) creates a second method which is not what you intended to do. 方法boolean equals(Subclass other)创建了第二个方法,该方法不是您想要的。

Two meta-points: 两个元点:

First, get in the habit of using @Override every time you believe you are overriding a method. 首先,养成每次您相信要覆盖方法时都使用@Override的习惯。 That would have caused your example code to fail to compile, leading you to discover the problem. 那会导致您的示例代码无法编译,从而导致您发现问题。

Second, if you're using an IDE, and it didn't highlight a nice bold warning for you, it is misconfigured! 其次,如果您使用的是IDE,但没有为您突出显示一个漂亮的粗体警告,则说明它配置错误! You should fix it! 您应该修复它!

And if you're not using an IDE -- you really, really should be. 而且,如果您不使用IDE,那么您确实应该这样做。 As soon as you typed public boolean equals(Subclass other) , the text would change color and a warning would be displayed telling you what your likely problem is. 键入public boolean equals(Subclass other) ,文本将更改颜色,并显示警告,告诉您可能的问题是什么。

Incidentally, the standard idiom for equals() that I've converged on is this: 顺便说一下,我聚合的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;
}

In some cases, it is worth prepending an if (object == this) { return true; } 某些情况下,值得在if (object == this) { return true; } if (object == this) { return true; } but it's really not worthwhile to make a regular habit of it. if (object == this) { return true; }但养成习惯确实不值得。

I had almost the same problem, as everyone said you need to override the right public boolean equals(Object o) method. 我遇到了几乎相同的问题,因为每个人都说您需要重写正确的public boolean equals(Object o)方法。 But that's not enough! 但这还不够!

It is also necessary to override public int hashCode() (as you did), otherwise, java wouldn't call the equals method at all. 还必须重写public int hashCode() (如您所做的那样),否则,java根本不会调用equals方法。

First guess, it looks like your equals(Subclass other) ought to be equals(Object other) in order to override the java.lang.Object.equals() method, as you want. 首先猜测,看起来您的equals(Subclass other)应该equals(Object other) ,以便根据需要重写java.lang.Object.equals()方法。 Probably the set is calling the underlying equals() implementation. 该集合可能正在调用底层的equals()实现。

Your equals method is never called. 您的equals方法永远不会被调用。 The signature of equals requires that it take an Object , not some other class (including whatever class happens to be implementing equals ). equals的签名要求它接受一个Object ,而不是其他一些类(包括碰巧实现equals任何类)。

public boolean equals(Object other) {
    ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM