设置只需要等于

时间:2015-04-27 02:02:06

标签: java

我很好奇,是否有Set只需要.equals()来确定唯一性?

查看Set中的java.util个类时,我只能找到需要HashSet.hashCode()的{​​{1}}(或通常为TreeSet)这需要SortedSet。我找不到任何只使用Comparator的课程。

如果我有.equals()方法,用它来确定对象唯一性就足够了吗?因此,.equals()实现只需要使用Set?或者我错过了.equals()不足以确定.equals()实施中对象唯一性的内容?

请注意,我知道Java实践,如果我们覆盖Set,我们应该覆盖.equals()以维护.hashCode()中定义的合同。

3 个答案:

答案 0 :(得分:4)

.equals方法本身就足以正确实现集合,但不能有效地实现

哈希码或比较器的要点是它们提供了在一些有序结构(哈希表或二叉树)中排列对象的方法,以便快速确定对象是否是出现在集合中。如果您只有.equals方法来比较对象对,则无法以任何有意义的顺序排列集合的内容;你只有一堆松散的对象,因此,例如,确认对象是唯一的,需要将每个添加的对象与混乱中的每个其他对象进行比较。

当然,你可以编写一个只使用.equals方法的正确集合,但它会很慢且不切实际。所以标准库中没有这样的实现。

此外,如果有这样的实施,它将鼓励违反Object类合同,.hashCode.equals必须相互一致。因此,它在标准库中的存在将是一个矛盾。它可能反过来伤害其他包含数据的类,这些类会担心使用不正确的.hashCode方法处理对象,并且会觉得有必要使用.equals - 仅将数据结构作为最小公分母,并且可能会伤到各地的表现实际上,类通常完全正确地假设其他类遵守Object类合同,并且可以在HashSetHashMap中使用它们。

对于它的价值,仅使用添加对象的Set方法的最小的,有效的.equals实现将是:

public class ArraySet<E> extends AbstractSet<E> {
    private final ArrayList<E> list = new ArrayList<>();

    @Override
    public boolean add(E e) {
        if (!list.contains(e)) {
            list.add(e);
            return true;
        }
        return false;
    }

    @Override
    public Iterator<E> iterator() {
        return list.iterator();
    }

    @Override
    public int size() {
        return list.size();
    }
}

此套装由ArrayList支持,并使用list.contains在对象上调用.equalsAbstractSetAbstractCollection的继承方法提供了Set接口的大部分功能;例如,它的.remove方法通过列表迭代器的.remove方法实现。添加或删除对象或测试其在集合中的成员资格的每个操作都有O( n )复杂度,其中 n 是当前集合中的对象数,因此它不是快速或可扩展的,但它在技术上可以正常工作。

从好奇心的角度来看这很有意思,但我不建议你使用它。相反,学习如何编写哈希码方法和比较器,并享受高效集和映射的好处。

答案 1 :(得分:3)

覆盖hashCode()时,总是覆盖equals()Object的合同明确规定两个相等的对象具有相同的哈希码,并且数量惊人的数据结构和算法依赖于此行为。添加hashCode()并不困难,如果您现在跳过它,当您的对象开始放入基于散列的结构时,您最终会得到难以诊断的错误。

答案 2 :(得分:2)

在数学上有意义设置除了.equals()之外什么都不需要。

但是这样的实现会很慢(每个操作的线性时间),因此决定你总是可以给出一个提示。

无论如何,如果真的没有办法写一个hashCode(),只要让它总是返回0,你的结构就会像你希望的那样慢!