Java:HashSet比较的概念是什么? 来自C++世界,我发现哈希集文档的阅读有些困难: 在C++中,你会有:
这反过来又指向:Java:HashSet比较的概念是什么? 来自C++世界,我发现哈希集文档的阅读有些困难: 在C++中,你会有:,java,set,language-concepts,Java,Set,Language Concepts,这反过来又指向: 这使得对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
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() );
}
}
根据我对文档的阅读,仅需要为Set实现equals运算符:
C++是一组“独特对象”,通常是“红黑树”。 在Java中,是一个更抽象的概念(它是一个接口,而不是一个类),具有多个实现,最显著的是和(忽略并发实现)
正如您可以从名字中猜到的,java <代码>树目录相当于C++ <代码> SET
对于需求,HashSet
使用和方法。它们是在对象
类上定义的,并且需要在需要位于或作为键位于的类上重写
对于和键,您有两个选项:在创建
树集
(类似于C++)时提供,或者让对象实现接口。我只是试图重现您的问题,可能您没有正确重写equals和/或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类时意识到了这个问题:
@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
这意味着我的错误很简单:
- 我一开始就有错误的签名:
!=<代码>布尔等于(标记t)布尔等于(对象o)
@Override
关键字
对于那些请求上游代码的人,Java代码由swig生成。原来的C++代码在这里:
hashCode
,因为默认的impl存在于object
中。这是否可以/应该优化是另一个问题。@malat你的例外毫无意义。如果<代码> > t1。等于(t2)< /> >和<代码> t1。HASCODE(=)=t2。HASCODE()/<代码> <代码> s siz()>代码>应为1,因为<代码> HasSET/<代码>将考虑<代码> T1和<代码> T2< /代码>相同。可能您提到的导致异常的代码不是您发布的代码。唯一的问题是,如果没有标记
实现,您就不会有异常。由于这个原因,可以认为这个问题是偏离主题的,因为我不能复制你的问题。C++ <代码> set <代码>包含一个类型的唯一类型的键值对象。排序是使用键比较函数<代码>比较< /代码>。Java的等价物是(不是HashSet
):元素按照其自然顺序排序,或者通过在集合创建时提供的Comparator
排序,具体取决于使用的构造函数。正如@Eran所提到的,不可能得到您声明的与发布的代码相关的异常。除非你故意破坏了equals
或hashCode
,否则请发布你的实际代码。破坏它的好方法。我只是使用了一个布尔值,第一次返回true,然后返回false。事实上,我对equals
函数使用了错误的签名,在我的例子中很难跟踪,因为我使用swig生成java代码。在java编程时,作为一般提示:始终使用@Override注释。如果您在将来的某个时候更改了一个超类的签名,然后突然发现子类的行为异常,这也会有所帮助。但是我现在要记住这个技巧:)谢谢你仔细阅读我的问题,事实上现在我看到了equals()
方法的正确签名。我现在明白了在JavaSet
中实际上是Set
,这对所有Java开发人员来说都是显而易见的(这解释了否决票),但是这对大多数C++程序员来说是违反直觉的。@马拉特的下投票(至少是我的)是因为你没有发布相关的代码,这会让你回答简单。“实际上是SET”,这远远不是正确的,java泛型比那时复杂得多,它们与C++模板非常不同。
gdcm/Tag.java:78: error: method does not override or implement a method from a supertype
@Override
^
1 error
1 warning