我正在寻找类似于 Java TreeSet 在实例化时接收自定义比较器的能力,因此我不需要使用对象的默认相等(和哈希码)标准。
我能想到的最接近的方法是将我的对象包装在一个私有自定义类中,但这似乎很棘手:(这最终成为编程时一种反复出现的主题,所以我想知道是否已经有一些东西可供我们使用。也许在公共图书馆?
谢谢
不,您已经找到了您应该使用的解决方案。
即使对于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());
有几个第三方集合框架允许自定义相等逻辑。这非常适合覆盖无法更改源的对象的相等性。
Trove 的地图/集支持使用自定义散列策略,允许您根据输入数据的特征调整集合。此功能还允许您在无法覆盖 Object.hashCode() 时定义散列函数。
为了实现这一点,任何需要标准校正的类型都必须实现 HE-Collection 接口 EqualsAndHashCorrection。该接口定义了 hashCodeInHeCollection() 和 equalsInHeCollection(Object) 方法,用于纠正错误实现的方法 hashCode() 和 equals(Object)。
你是对的,当你想使用任何Trees
( TreeMap
, TreeSet
) 你添加的对象必须实现Comparable
。
对于原始类型,Java 已经为您解决了这个问题。
对于自定义对象,您有 3 种可能性:
您的一个对象已经具有原始类型的唯一 id 或已经实现的类型compareTo()
(如String
)如果其他对象的值对于相等性不重要,则将此字段用于 compareTo。(但equals()
也必须只使用这一个字段)
从 Apache使用EqualsBuilder
:这适用于反射,并不是最快的解决方案
自己写,阅读一些教程如何做到这一点:例如:
Josh Bloch:有效的 Java 第 2 版
但是不要忘记equals()
, 和compareTo()
必须兼容(和hashCode()
, 也是),这样你就不会违反 equals 契约。(合同本身不太容易理解,但如果你拒绝其中一个等于教程,就会清楚。)
或者忘记这一切,并使用HashSet
, HashMap
。