JDK java.util.concurrent.ConcurrentSkipListSet.equals(对象o)实现效率
JDK中JDK java.util.concurrent.ConcurrentSkipListSet.equals(对象o)实现效率,java,performance,collections,iterator,openjdk,Java,Performance,Collections,Iterator,Openjdk,JDK中等于java.util.concurrent.ConcurrentSkipListSet的实现如下 public boolean equals(Object o) { // Override AbstractSet version to avoid calling size() if (o == this) return true; if (!(o instanceof Set)) return false; Collect
等于java.util.concurrent.ConcurrentSkipListSet
的实现如下
public boolean equals(Object o) {
// Override AbstractSet version to avoid calling size()
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection<?> c = (Collection<?>) o;
try {
return containsAll(c) && c.containsAll(this);
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}
}
输出结果
true
2713
true
589
在JDK评论中,它说,这个定义确保equals方法在set接口的不同实现中正常工作。
有人能解释一下吗?作为参考,结果是创建了
JDK评论中说,这个定义确保equals方法在set接口的不同实现中正常工作。
有人能解释一下吗
它来自中国。根据文件:
如果指定的对象也是一个集合,两个集合的大小相同,并且指定集合的每个成员都包含在此集合中(或者等效地,此集合的每个成员都包含在此指定集合中),则返回true。此定义确保equals方法在set接口的不同实现中正常工作
这意味着Set.equals
实现应该由的行为定义。这就引出了下面的一段话:
请注意,如果排序集要正确实现set接口,则排序集维护的排序(无论是否提供显式比较器)必须与equals一致。(请参阅Comparable interface或Comparator interface以获得与equals一致的精确定义。)这是因为Set interface是根据equals操作定义的,但排序集使用其compareTo(或compare)方法执行所有元素比较,因此此方法认为相等的两个元素是,从排序集的角度来看,相等。即使排序集的顺序与equals不一致,排序集的行为也是定义良好的;它只是没有遵守Set接口的总合同
那么为什么在ConcurrentSkipListSet
中出现“this contains that and that contains this”?首先,您希望避免呼叫,因为:
请注意,与大多数集合不同,此方法不是常数时间操作。由于这些集合的异步性质,确定当前元素的数量需要遍历它们以对它们进行计数。此外,在执行此方法的过程中,可能会更改大小,在这种情况下,返回的结果将不准确。因此,这种方法在并发应用程序中通常不是很有用
第二个原因是你想“与平等保持一致”
让我们根据您的代码制作一个残酷的示例:
private static boolean myEquals(Set o1, Set o2) {
if (o1.size() == 1 && o2.size() == 1) {
Iterator ic = o2.iterator();
Iterator id = o1.iterator();
while (ic.hasNext() && id.hasNext()) {
if (!ic.next().equals(id.next())) {
return false;
}
}
return true;
}
return o1.equals(o2);
}
public static void main(String[] args) {
print(skiplist(new BigDecimal("1.0")), tree(new BigDecimal("1.00")));
print(skiplist(new BigDecimal("1.0")), hash(new BigDecimal("1.00")));
print(skiplist(new BigDecimal("1.0")), identity(new BigDecimal("1.00")));
print(skiplist(BigDecimal.ONE), identity(new BigDecimal(BigInteger.ONE, 0)));
}
private static Collection<BigDecimal> e() {
return Arrays.asList(new BigDecimal("1.0"));
}
private static <E> Set<E> hash(E... e) {
return new HashSet<>(Arrays.asList(e));
}
private static <E> Set<E> skiplist(E... e) {
return new ConcurrentSkipListSet<>(Arrays.asList(e));
}
private static <E> Set<E> tree(E... e) {
return new TreeSet<>(Arrays.asList(e));
}
private static <E> Set<E> identity(E... e) {
Set<E> s = Collections.newSetFromMap(new IdentityHashMap<E, Boolean>());
Collections.addAll(s, e);
return s;
}
private static void print(Set o1, Set o2) {
System.out.println(o1.getClass().getName()
+ "==" + o2.getClass().getName() + ": "
+ o1.equals(o2) + ": " + myEquals(o1, o2));
System.out.println(o2.getClass().getName()
+ "==" + o1.getClass().getName() + ": " + o2.equals(o1)
+ ": " + myEquals(o2, o1));
}
该结果表明,新的实施不会:
当且仅当e1.compareTo(e2)==0对于C类的每个e1和e2具有与e1.equals(e2)相同的布尔值时,C类的自然顺序称为与equals一致。请注意,null不是任何类的实例,即使e.equals(null)返回false,e.compareTo(null)也应抛出NullPointerException
现在我们可以通过将元素检查替换为
((可比)e1)。可比((可比)e2)!=0
或比较器。比较(e1,e2)!=0
并添加检查,以尝试确定两个集合使用相同的顺序,但请记住,集合可以包装,并且没有任何东西可以阻止调用方。现在您回到了equals的“this contains that and that contains this”实现,它可以处理集合包装器
“this contains that and that contains this”实现的另一个很好的属性是,equals实现没有为给定集合创建迭代器对象,而在最坏的情况下,该集合可能会有一个类似于Arrays.asList(s.toArray()).iterator()的实现
如果不放松规范,放松现有行为,或者添加一个返回a的集合方法来捕获集合的“等价关系”,我认为很难将这样的优化添加到JDK中。您的代码假设两个集合都是有序的。他们的没有。@EJP实际上是ConcurrentSkipListSet
extendsNavigableSet
扩展SortedSet
请在核心库中讨论您的问题-dev@openjdk.java.net邮件列表。谢谢@Fairoz,我稍后会发布。抱歉@EJP,我误解了,这个
是有序的,但是的参数等于()
即。,对象o
可能未排序。谢谢
true
2713
true
589
private static boolean myEquals(Set o1, Set o2) {
if (o1.size() == 1 && o2.size() == 1) {
Iterator ic = o2.iterator();
Iterator id = o1.iterator();
while (ic.hasNext() && id.hasNext()) {
if (!ic.next().equals(id.next())) {
return false;
}
}
return true;
}
return o1.equals(o2);
}
public static void main(String[] args) {
print(skiplist(new BigDecimal("1.0")), tree(new BigDecimal("1.00")));
print(skiplist(new BigDecimal("1.0")), hash(new BigDecimal("1.00")));
print(skiplist(new BigDecimal("1.0")), identity(new BigDecimal("1.00")));
print(skiplist(BigDecimal.ONE), identity(new BigDecimal(BigInteger.ONE, 0)));
}
private static Collection<BigDecimal> e() {
return Arrays.asList(new BigDecimal("1.0"));
}
private static <E> Set<E> hash(E... e) {
return new HashSet<>(Arrays.asList(e));
}
private static <E> Set<E> skiplist(E... e) {
return new ConcurrentSkipListSet<>(Arrays.asList(e));
}
private static <E> Set<E> tree(E... e) {
return new TreeSet<>(Arrays.asList(e));
}
private static <E> Set<E> identity(E... e) {
Set<E> s = Collections.newSetFromMap(new IdentityHashMap<E, Boolean>());
Collections.addAll(s, e);
return s;
}
private static void print(Set o1, Set o2) {
System.out.println(o1.getClass().getName()
+ "==" + o2.getClass().getName() + ": "
+ o1.equals(o2) + ": " + myEquals(o1, o2));
System.out.println(o2.getClass().getName()
+ "==" + o1.getClass().getName() + ": " + o2.equals(o1)
+ ": " + myEquals(o2, o1));
}
java.util.concurrent.ConcurrentSkipListSet==java.util.TreeSet: true: false
java.util.TreeSet==java.util.concurrent.ConcurrentSkipListSet: true: false
java.util.concurrent.ConcurrentSkipListSet==java.util.HashSet: false: false
java.util.HashSet==java.util.concurrent.ConcurrentSkipListSet: false: false
java.util.concurrent.ConcurrentSkipListSet==java.util.Collections$SetFromMap: false: false
java.util.Collections$SetFromMap==java.util.concurrent.ConcurrentSkipListSet: false: false
java.util.concurrent.ConcurrentSkipListSet==java.util.Collections$SetFromMap: false: true
java.util.Collections$SetFromMap==java.util.concurrent.ConcurrentSkipListSet: false: true