番石榴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)得到不同的集合
,这非常糟糕,因为并集应该是可交换的。