-2

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

在 c++ 中,您将拥有:

这又指向:

这使得对 a 处理的元素类型的要求很明显std::setSet我的问题是: Java 中a 维护的元素类型 (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 实现 equals 运算符:

我从文档中遗漏了什么?

4

3 回答 3

3

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

看看我对 Tag 的错误实现:

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;
}
于 2017-10-02T07:16:10.767 回答
1

我从文档中遗漏了什么?

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

C++set“一组有序的唯一对象”,并且“通常实现为红黑树”。

在 Java 中,Set是一个更抽象的概念(它是一个接口,而不是一个类),具有多个实现,最显着的是 theHashSet和 the (忽略并发实现)TreeSet

正如您可能仅从名称中猜到的那样,JavaTreeSet相当于 C++ set

至于要求,HashSet使用hashCode()equals()方法。它们是在Object类上定义的,并且需要在需要位于 a 中HashSet或作为 a 中的键的类上被覆盖HashMap

对于TreeSet和 的键TreeMap,您有两个选择:Comparator在创建时提供一个TreeSet(类似于 C++),或者让对象实现Comparable接口。

于 2017-10-02T07:03:11.883 回答
0

我想这只是运气不好和对 HashSet 要求的误解的结合。感谢@christophe 的帮助,当我尝试添加 swig 生成的 Tag.java 类时,我意识到了这个问题:

@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++ 代码在这里:

于 2017-10-02T07:31:45.240 回答