我一直在尝试理解 HashSet 的行为方式,但遇到了这个我无法理解的问题。第二个和第三个狗对象具有相同的名称,并且 equals()
和hashcode()
已被覆盖以使名称意味着平等。尽管如此,hashSet 仍然有重复项,我不明白为什么。
我重读了 Head First Java 的数据结构章节,但它仍然表明我的代码理论上应该可以工作。
public class DataStructsTests<E> {
HashSet<Dogs> tree = new HashSet<Dogs>();
HashSet<Dogs> treeOwner = new HashSet<Dogs>();
public static void main(String[] args) {
DataStructsTests<String> d = new DataStructsTests<String>();
d.go();
}
public void go() {
Dogs dog = new Dogs("Scout", "a");
tree.add(dog);
treeOwner.add(dog);
Dogs dog2 = new Dogs("Brodie", "b");
tree.add(dog2);
treeOwner.add(dog2);
Dogs dog3 = new Dogs("Brodie", "c");
tree.add(dog3);
treeOwner.add(dog3);
System.out.println(tree);
System.out.println(treeOwner);
System.out.println(dog2.equals(dog3));
System.out.println(dog2.hashCode() + " " + dog3.hashCode());
}
class Dogs {
private String name;
private String ownerName;
public Dogs(String n, String o) {
name = n;
ownerName = o;
}
public boolean equals(Dogs d) {
return name.equals(d.getName());
}
public int hashCode() {
return name.hashCode();
}
public String getName() {
return name;
}
public String toString() {
return name;
}
运行程序返回:
[Brodie, Brodie, Scout]
[Brodie, Brodie, Scout]
true
1998211617 1998211617
尽管equals()
返回 true 并且哈希码相同,重复项仍然存在。
编辑:原来问题是我没有正确重写 equals() 方法,因为我使用的是 Dog 而不是 Object。
最佳答案
equals
采用 Object
类型的对象,该对象由 HashSet
调用。你需要这样的东西:
@Override
public boolean equals(Object d) {
if (! d instanceof Dogs){
return false;
}
return name.equals(((Dogs) d).getName());
}
以下是该答案的组成部分:
public boolean equals(Object d)
-equals
,至少从Object
继承的版本,被定义为采用Object
,因此要覆盖它,您还必须获取一个Object
。@Override
- 如果您犯了像问题中那样的错误,则告诉编译器向您发出警告。d instanceof Dogs
- 首先检查输入的Object
是否是Dogs
。((Dogs) d).getName()
- 转换为Dogs
的原因是因为d
现在正在传入作为Object
,因此您不会自动获得对Dogs
方法的访问权限,除非您明确表示要将Object
查看为一只狗
。
最后一点:Java 中的一般约定是以单数命名类,除非有某种理由相信每个实例将是多个事物。这是为了避免歧义。 Dog d
明确了 d
是什么;它显然是一只狗
。 Dogs d
到底是什么? d
狗很多,但它们只是没有自己的对象类型?它变得有点模棱两可。
关于java - Java 中的 Hashset 出现这种奇怪行为的原因是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56429544/