【发布时间】:2020-03-18 12:20:15
【问题描述】:
SortedSet<T> 是Set<T> 的实现,它维护T 类型元素的排序。
我很难理解为什么有必要按照以下文档实施SortedSet 的equals 方法,从而破坏Set 的一般合同:
请注意,如果有序集合要正确实现
Set接口,则由有序集合维护的排序(无论是否提供显式比较器)必须与equals 一致。 (参见Comparable接口或Comparator接口,了解与equals 一致的精确定义。)这是因为Set 接口是根据equals 操作定义的,但排序集使用其@987654335 执行所有元素比较@(或比较)方法,因此从排序集的角度来看,此方法认为相等的两个元素是相等的。一个有序集合的行为是明确定义的,即使它的排序与equals不一致;它只是不遵守Set接口的一般约定。
当前实现
通过浏览源代码,SortedSet 的相等性似乎目前以下列方式工作。给定两个SortedSet 实例a 和b,a.equals(b) 将:
- 将比较委托给
AbstractSet#equals(Object o)- 检查无效性、转换问题并确保集合大小相等
- 致电
AbstractCollection#containsAll(Collection<?> c)- 循环遍历
c中的所有元素e,并为每个元素调用this.contains(e)。
- 循环遍历
- 分派到特定的
Collection#contains(Object o)implementation,例如TreeSet#contains。 - 以
TreeSet<T>及其支持NavigableMap<T>(通常为TreeMap<T>)为例,我们可以看到调用落入TreeMap#containsKey(Object key)。- 这会检查
TreeMap#getEntry(key)是否不是null。
- 这会检查
- 至关重要的是,代码如下所示:
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
直观的SortedSet平等
要确定两个 SortedSet 实例 a 和 b 是否相等,我个人会:
- 在当前实现中执行相同的初始检查,例如大小比较
- 在集合
a的第一个元素上启动光标 - 在集合
b的第一个元素上启动光标 - 将元素与自己的
equals方法进行比较 - 将两个光标移动到下一个元素并转到第 4 步,直到元素用完为止。
由于排序顺序是由Comparator 或compareTo 方法保证的,所以我看不出这不起作用的原因。
问题
- 我上面的方法有问题吗?
- 如果不是,为什么
SortedSet不相等?
【问题讨论】: