Java:HashSet什么是Compare概念?

时间:2017-10-02 06:38:54

标签: java set language-concepts

来自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:

实现equals运算符

文档中缺少什么?

4 个答案:

答案 0 :(得分:2)

我只是尝试重现您的问题,也许您只是没有正确覆盖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;
}

答案 1 :(得分:1)

  

文档中缺少什么?

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

C ++ set是一个“排序的唯一对象集”,并且“通常实现为红黑树。”

在Java中,Set是一个更抽象的概念(它是一个接口,而不是一个类),具有多个实现,最值得注意的是HashSetTreeSet (忽略并发)实现)

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

对于要求,HashSet使用hashCode()equals()方法。它们是在Object类上定义的,需要在需要HashSet的类或HashMap中的键中重写。

对于TreeSetTreeMap的密钥,您有两种选择:在创建TreeSet(类似于C ++)时提供Comparator,或让对象实现Comparable界面。

答案 2 :(得分: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 ++代码在这里:

答案 3 :(得分:-3)

大小为2(不等于1),因此抛出异常(最后一行代码)。 编辑:也许我以前没有理解你。通常,类型E是您选择的任何类型。例如:put Object或&#39;?&#39;会让你能够放任何类型。在您的情况下,您选择标记作为类型E,因此它应该是集合的内容。