通用技术 HashSet 什么情况下会有两个相同的元素?

在路上 · 2018年03月28日 · 最后由 在路上 回复于 2018年03月28日 · 2560 次阅读

什么是 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;
    }
}

输出结果如下:

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
最佳回复
槽神 回复

hashCode = count 值,元素是相同的,只不过存储位置不同。
因为 first(count=3) 元素存储在了 hashCode 值为 3 的地方,已经存进去了,即使修改了 count(修改为-3) 值,使得元素的 hashCode 值也改变为-3,但是存储位置没变。
所以,c1.contains(new R(-3)) 返回 false,因为 new R(-3) 去 hashSet 中寻找的是 hashCode 为-3 的存储位置,但是已经被删除了,所以返回 false

共收到 2 条回复 时间 点赞

first.count = 3,并未改变 R(-3) 的 hashCode,所以他们不是相同的

槽神 回复

hashCode = count 值,元素是相同的,只不过存储位置不同。
因为 first(count=3) 元素存储在了 hashCode 值为 3 的地方,已经存进去了,即使修改了 count(修改为-3) 值,使得元素的 hashCode 值也改变为-3,但是存储位置没变。
所以,c1.contains(new R(-3)) 返回 false,因为 new R(-3) 去 hashSet 中寻找的是 hashCode 为-3 的存储位置,但是已经被删除了,所以返回 false

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册