48

我正在寻找类似于 Java TreeSet 在实例化时接收自定义比较器的能力,因此我不需要使用对象的默认相等(和哈希码)标准。

我能想到的最接近的方法是将我的对象包装在一个私有自定义类中,但这似乎很棘手:(这最终成为编程时一种反复出现的主题,所以我想知道是否已经有一些东西可供我们使用。也许在公共图书馆?

谢谢

4

3 回答 3

18

不,您已经找到了您应该使用的解决方案。

即使对于TreeSet,也不赞成使用与 不兼容的比较标准equals

请注意,如果有序集合要正确实现 Set 接口,则由有序集合维护的排序(无论是否提供显式比较器)必须与 equals 一致。

我不了解 Apache Commons,但 Guava明确 拒绝了此类请求,尽管您可以使用Guava Equivalence实现您想要的:

Equivalence<T> equivalence = new Equivalence<T>() {
    @Override
    protected boolean doEquivalent(T a, T b) {
        return CustomComparator.equals(a, b);
    }

    @Override
    protected int doHash(T item) {
        return CustomHashCodeGenerator.hashCode(item);
    }
};
List<T> items = getItems();
Set<Equivalence.Wrapper<T>> setWithWrappedObjects = items.stream()
    .map(item -> equivalence.wrap(item))
    .collect(Collectors.toSet());
于 2013-02-14T17:20:36.560 回答
4

有几个第三方集合框架允许自定义相等逻辑。这非常适合覆盖无法更改源的对象的相等性。

Trove 的地图/集支持使用自定义散列策略,允许您根据输入数据的特征调整集合。此功能还允许您在无法覆盖 Object.hashCode() 时定义散列函数。

为了实现这一点,任何需要标准校正的类型都必须实现 HE-Collection 接口 EqualsAndHashCorrection。该接口定义了 hashCodeInHeCollection() 和 equalsInHeCollection(Object) 方法,用于纠正错误实现的方法 hashCode() 和 equals(Object)。

于 2013-02-14T18:11:32.960 回答
3

你是对的,当你想使用任何Trees( TreeMap, TreeSet) 你添加的对象必须实现Comparable

对于原始类型,Java 已经为您解决了这个问题。
对于自定义对象,您有 3 种可能性:

  1. 您的一个对象已经具有原始类型的唯一 id 或已经实现的类型compareTo()(如String)如果其他对象的值对于相等性不重要,则将此字段用于 compareTo。(但equals()也必须只使用这一个字段)

  2. 从 Apache使用EqualsBuilder:这适用于反射,并不是最快的解决方案

  3. 自己写,阅读一些教程如何做到这一点:例如:

Josh Bloch:有效的 Java 第 2 版

但是不要忘记equals(), 和compareTo()必须兼容(和hashCode(), 也是),这样你就不会违反 equals 契约。(合同本身不太容易理解,但如果你拒绝其中一个等于教程,就会清楚。)

或者忘记这一切,并使用HashSet, HashMap

于 2013-02-14T17:30:28.680 回答