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