首页 > 解决方案 > 如何修复允许重复的 HashSet?

问题描述

我正在使用带有java.util.HashSet实现的java.util.Set接口并将其存储在 Map 中。

我将一个对象添加到 Set 然后再次检索 Set 对象,并且能够添加另一个与第一个对象相等的对象。

添加看似相等的对象时,Set.add返回true,两个相等的对象存储在一个 HashSet 中。这怎么可能?我能做些什么来解决这个明显的 Set 合同破裂?

我正在通过 IntelliJ IDEA 2018.3.6 使用 Java 12,并检查了我的java.lang.Object.hashCode实现,以了解我添加到 Set 中的两个对象的类,两者都返回相同的哈希码。我还检查了java.lang.Objects.equals实现,并true在使用该方法检查它们的相等性时返回。两个对象都包装在另一个对象 Entity 中,但它只转发对象hashCodeequals实现。

class Model {

    ...

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Offer)) {
            return false;
        }

        Offer offer = (Offer) obj;
        return Objects.equals(id, offer.id)
            && Objects.equals(name, offer.name)
            ;
    }

    @Override
    public int hashCode() {
        int result = 1;
        result = 31 * result + Objects.hashCode(id);
        result = 31 * result + Objects.hashCode(name);
        return result;
    }

    ...

}
class Store {

    ...

    private static class Entry {
        Object value;

        Entry(Object value) {
            this.value = value;
        }

        Object getValue() {
            return value;
        }

        @Override
        public boolean equals(Object obj) {
            return Objects.equals(value, obj);
        }

        @Override
        public int hashCode() {
            return value.hashCode();
        }

        @Override
        public String toString() {
            return "Entry[value = " + value + "]";
        }
    }

    ...

    private Map<Class<?>, Set<Entry>> data;

    ...

    private Set<Entry> get(Class<?> type) {
        return data.getOrDefault(type, new HashSet<>());
    }

    @Override
    public void persist(Object obj) {
        Entry entry = new Entry(obj);
        Set<Entry> objects = get(obj.getClass());
        if (objects == null) {
            objects = new HashSet<>();
        }
        if (!objects.add(entry)) {
            throw new ObjectExistsException
                ("Object already exists: " + obj);
        }
        data.put(obj.getClass(), objects);
    }

    ...

}

obj1obj2类型 Model 相等并且objects已经包含obj1在一个 Entry 对象中时,我希望obj2不要添加到objectswhenobj2被包装entryobjects.add(entry)返回false然后抛出 ObjectExistsException 的时候。

然而,实际发生的是返回objects.add(entry)并被true添加到.obj2entityobjects

标签: javasethashset

解决方案


    @Override
    public boolean equals(Object obj) {
        return Objects.equals(value, obj);
    }

这不是Entry.equals. 这可能会将 aEntry与当前条目保存的值进行比较。(就像比较一封信和一个信封)。

让您的 equals 方法检查obj是否为Entry,并获取其值,并检查是否相等。


推荐阅读