什么是 HashSet

HashSet 是一个集合类,也可理解为一个容器。用来盛装各种元素,无顺序且不可重复。

HashSet 存储方式

当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据该 hashCode 值来决定该对象在 HashSet 中的存储位置。
如果有两个元素通过 equals 方法比较返回 true,但是他们的 hashCode() 方法返回值不相等,HashSet 会将他们存储在不同位置,也就可以添加成功。

什么情况下,会出现 HashSet 中包含 equals 相等,且 hashCode 值也相等的两个元素呢?

如果向 HashSet 中添加一个可变对象后,并且后面程序修改了该可变对象的属性,可能导致它与集合中其他元素相同 (即两个对象通过 equals 方法比较返回 true,两个对象的 hashCode 值也相等),这就有可能导致 HashSet 中包含两个相同的对象。

如下代码所示:

public class TestHashSet {
    public static void main(String[] args) {
        Collection c1 = new HashSet();
        c1.add(new R(-3));
        c1.add(new R(5));
        c1.add(new R(8));
        c1.add(new R(3));

        //false
        System.out.println(c1.add(new R(-3)));

        //[R(count属性:-3), R(count属性:3), R(count属性:5), R(count属性:8)]
        System.out.println(c1);

        Iterator it = c1.iterator();
        R first = (R)it.next();
        //first.count = 3,但是first.hashCode = -3
        first.count = 3;

        //[R(count属性:3), R(count属性:3), R(count属性:5), R(count属性:8)]
        System.out.println(c1);

        //删除和new R(3)的hashCode一样,且equals(new R(3))为true的元素
        c1.remove(new R(3));

        //[R(count属性:3), R(count属性:5), R(count属性:8)]
        System.out.println(c1);

        //false
        System.out.println("c1是否包含count为-9的元素?" + c1.contains(new R(3)));

        //false
        System.out.println("c1是否包含count为5的元素?" + c1.contains(new R(-3)));

    }
}

class R {
    int count;

    //构造函数
    public R(int count) {
        this.count = count;
    }

    //重写toString()方法
    @Override
    public String toString() {
        return "R(count属性:" + count + ")";
    }

    //重写equals()方法,
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof R) {
            R r = (R)obj;
            if (r.count == this.count) {
                return true;
            }
        }
        return false;
    }

    //重写hashCode()方法
    @Override
    public int hashCode() {
        return this.count;
    }
}

输出结果如下:


↙↙↙阅读原文可查看相关链接,并与作者交流