番石榴JavaDocs所说的基于不同“的集合是什么意思?”;等价关系;?

番石榴JavaDocs所说的基于不同“的集合是什么意思?”;等价关系;?,java,collections,set,guava,equivalence,Java,Collections,Set,Guava,Equivalence,set.SetView.union()(以及intersection()、difference()、和symmetricDifference())的番石榴提到了“等价关系”: 如果set1和set2是基于不同的等价关系(如HashSet,TreeSet,以及IdentityHashMap的Map.keySet())设置的,则结果是未定义的 我很难理解那句话的意思 术语表(“a.relationship(a)总是true”)、(a1.relationship(a2)=a2.relationship

set.SetView.union()
(以及
intersection()
difference()
、和
symmetricDifference()
)的番石榴提到了“等价关系”:

如果
set1
set2
是基于不同的等价关系(如
HashSet
TreeSet
,以及
IdentityHashMap
Map.keySet()
)设置的,则结果是未定义的

我很难理解那句话的意思

术语表(“
a.relationship(a)
总是
true
”)、(
a1.relationship(a2)=a2.relationship(a1)
)和(
a1.relationship(a2)&&a2.relationship(a3)
意味着
a1.relationship(a3)
)-并引用。(不幸的是,报告没有详细说明


但是不同类型的
集合
在这方面有什么不同(即等价关系)?它们似乎都是继承的?这与集合持有的对象类型无关(例如
集合
集合
),是吗?

这听起来像是指当
集合
出于某种原因不使用
等于
哈希码
来比较元素时。最常见的例子是带有自定义
比较器的
树集
。例如,我们可以有这样的东西:

Set<String> a = new TreeSet<>();
Set<String> b = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
Set a=new TreeSet();
Set b=新树集(字符串不区分大小写顺序);
a
b
的并集、交集等未定义,因为
a
b
在元素之间定义了不同的等价关系

Java SE在谈到排序时也提到了这种情况,这种排序与
equals
不一致(请参阅):

请注意,如果要正确实现
set
接口,集合维护的顺序(无论是否提供显式比较器)必须与equals一致。(有关与equals一致的精确定义,请参见
Comparable
comparator
)这是因为
Set
接口是根据
equals
操作定义的,但是
TreeSet
实例使用其
compareTo
(或
compare
)执行所有元素比较方法,因此,从集合的角度来看,被此方法视为相等的两个元素是相等的。集合的行为是明确定义的,即使其顺序与相等不一致;它只是未能遵守
集合
接口的总合同


这让我有点困惑。对我来说,实现
Set.union
似乎很容易,这样它就可以在不同的等价关系中正常工作。集合只是一个谓词和迭代器,所以
union(a,b)
就是
contains(x):a.contains(x)和&b.contains(x)
iterator():a.iterator().concat(b.iterator()).filter(x->!a.contains(x)))
也许java.util.Set中有一些我没有注意到的细微之处,对于具有不同等价关系的集合,这个简单的实现会有问题吗?@MikeFHay我认为问题在于以一种有意义的方式为联合结果创建一个
集合ave将结果返回到另一个标识集中,否则它将看起来“不正确”,因为重复的元素(根据
集合
合同)将被删除。如果我们在一个标识集中返回结果,它将打乱正常集合的联合。如果Java有更好的克隆API,这可以部分解决,但不适用于集合具有不同等价关系的情况。我认为您的示例不能准确地表示问题。Guava文档说,
结果未定义如果set1和set2是基于不同等价关系的集合
,则为ed,但在您的示例中,您将两个具有相同等价关系(标识)的集合进行并集。此外,Guava的
union
是一个视图-它实际上并没有创建新的集合,只是使用现有集合实现集合接口,正如我在评论中所述。选择新实现的问题不是这种方法的问题。@Mikeffhay如果将集合与不同的等价关系混合,则问题是sa正如我的例子所指出的那样,使用我的例子中的集合,union可以是
[X,X]
[X]
,这取决于使用的等价关系。在Guava的例子中,JavaDoc定义迭代顺序的方式,实际上可以为
union(a,b)
union(b,a)得到不同的集合
,这非常糟糕,因为并集应该是可交换的。