Java:HashSet Compare是什么概念?

Java: HashSet what is the Compare concept?

来自 c++ 世界,我发现阅读 HashSet 文档有些困难:

在 C++ 中,您将拥有:

依次指向:

这使得 std::set 处理的元素类型的要求显而易见。我的问题是:Java 中的 Set 维护的元素类型 (E) 有什么要求?

这是一个我无法理解的简短示例:

import gdcm.Tag;
import java.util.Set;
import java.util.HashSet;

public class TestTag
{
  public static void main(String[] args) throws Exception
    {
      Tag t1 = new Tag(0x8,0x8);
      Tag t2 = new Tag(0x8,0x8);
      if( t1 == t2 )
        throw new Exception("Instances are identical" );
      if( !t1.equals(t2) )
        throw new Exception("Instances are different" );
      if( t1.hashCode() != t2.hashCode() )
        throw new Exception("hashCodes are different" );
      Set<Tag> s = new HashSet<Tag>();
      s.add(t1);
      s.add(t2);
      if( s.size() != 1 )
        throw new Exception("Invalid size: " + s.size() );
    }
}

上面的简单代码失败了:

Exception in thread "main" java.lang.Exception: Invalid size: 2 at TestTag.main(TestTag.java:42)

根据我对文档的阅读,只有等于运算符需要为 Set 实现:

文档中缺少什么?

What am I missing from the documentation ?

您正在查看文档的错误部分。

C++ set 是一个 "sorted set of unique objects",并且是 "usually implemented as red-black trees."

在Java, Set is a more abstract concept (it's an interface, not a class) with multiple implementations, most notably the HashSet and the TreeSet (忽略并发实现).

您可能仅从名称就可以猜到,Java TreeSet 等同于 C++ set.

至于要求,HashSet 使用 hashCode() and equals() methods. They are defined on the Object class, and needs to be overridden on classes that needs to be in a HashSet or as keys in a HashMap

对于TreeSet and keys of TreeMap, you have two options: Provide a Comparator when creating the TreeSet (similar to C++), or have the objects implement the Comparable接口。

我只是试图重现您的问题,也许您只是没有正确覆盖 equals and/or hashSet。

看看我对标签的错误实现:

public class Tag {

private int x, y;

public Tag(int x, int y) {
    this.x = x;
    this.y = y;
}

public boolean equals(Tag tag) {
    if (x != tag.x) return false;
    return y == tag.y;
}

@Override
public int hashCode() {
    int result = x;
    result = 31 * result + y;
    return result;
}
}

看起来还不错吧?但问题是,我实际上并没有覆盖正确的 equals 方法,我用自己的实现重载了它。

要正常工作,equals 必须如下所示:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Tag tag = (Tag) o;

    if (x != tag.x) return false;
    return y == tag.y;
}

我想这只是运气不好和对 HashSet 要求的误解的结合。感谢@christophe 的帮助,当我尝试添加生成的 swig Tag.java class:

时,我意识到了这个问题
@Override
public boolean equals(Object o) {
}

我收到以下错误消息:

gdcm/Tag.java:78: error: method does not override or implement a method from a supertype
  @Override
  ^
1 error
1 warning

这意味着我的错误很简单:

  • 我一开始签名就错了:boolean equals(Object o) != boolean equals(Tag t)

提示只是使用 @Override 关键字。


对于那些要求上游代码的人,Java 代码是由 swig 生成的。原始c++代码在这里: