HashSet存储相等的对象

4
以下是查找对象列表中重复对象的代码。但由于某些原因,HashSet 甚至存储了相等的对象。
我肯定在这里漏掉了一些东西,但当我检查 HashSet 的大小时,它显示为 5。
import java.util.ArrayList;
import java.util.HashSet;


public class DuplicateTest {

public static void main(String args[]){
    ArrayList<Dog> dogList = new ArrayList<Dog>();
    ArrayList<Dog> duplicatesList = new ArrayList<Dog>();
    HashSet<Dog> uniqueSet = new HashSet<Dog>();

    Dog a = new Dog();
    Dog b = new Dog();
    Dog c = new Dog();
    Dog d = new Dog();
    Dog e = new Dog();

    a.setSize("a");
    b.setSize("b");
    c.setSize("c");
    d.setSize("a");
    e.setSize("a");

    dogList.add(a);
    dogList.add(b);
    dogList.add(c);
    dogList.add(d);
    dogList.add(e);

    if(a.equals(d)){
        System.out.println("two dogs are equal");
    }
    else System.out.println("dogs not eqal");

    for(Dog dog : dogList){
        uniqueSet.add(dog);
    }

    System.out.println("number of unique dogs="+ uniqueSet.size());
    /*for(Dog dog:uniqueSet){
        System.out.println("uniqueset ="+dog.getSize());
    }

    for(Dog dog : duplicatesList){
        System.out.println("duplicate dog="+dog.getSize());
    }*/

}

}

这里是 Dog 类

public class Dog implements Animal, Comparable<Dog>{

String size;

public void makeNoise(){
    System.out.println("woof woof");
}

public String getSize() {
    return size;
}

public void setSize(String size) {
    this.size = size;
}

public int compareTo(Dog d){
    return this.size.compareTo(d.size);
}

public boolean equals(Dog d){
    return this.size.equals(d.size);
}

@Override
public int hashCode() {
    // TODO Auto-generated method stub
    return super.hashCode();
}
}
1个回答

8

这段代码不能满足你的需求:

public boolean equals(Dog d){
    return this.size.equals(d.size);
}

这并没有覆盖Object.equals方法,而HashSet使用的是该方法。你需要:

@Override
public boolean equals(Object d){ 
    if (!(d instanceof Dog)) {
        return false;
    }
    Dog dog = (Dog) d;
    return this.size.equals(dog.size);
}

请注意,使用@Override注释时,您正在请求编译器验证您实际上正在覆盖该方法。
编辑:如前所述,您还需要以与equals方法兼容的方式覆盖hashCode。考虑到您基于大小检查相等性,最简单的选项是:
@Override
public int hashCode() {
    return size.hashCode();
}

此外,OP还必须以不同的方式覆盖hashCode,因为现在他所做的是两个大小相同的不同狗具有不同的哈希码。由于OP似乎使用一个字符字符串表示狗的大小,因此一种可能性是使用return size.charAt(0); - halex
@halex:是的,我没有注意到。我会进行编辑。(但我不只是使用 charAt(0)...最好使用大小哈希码...) - Jon Skeet
你只使用size的哈希码的解决方案确实更好,我不得不承认:)+1 - halex
嗯...为什么需要实现hashCode()方法呢?如果我的代码说当满足某个条件时两个对象相等,那么编译器为什么还要去检查hashCode呢?我理解在HashMap中hashCode的重要性,但是在Set中为什么也需要呢? - antnewbee
@antnewbee:你正在使用HashSet。提示在于Hash这个部分 :) 如果你使用了TreeSet,它会使用compareTo...但是你正在使用基于普通相等性/哈希的HashSet。(而且调用hashCode的不是编译器,而是HashSet内部的代码。) - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接