JDK中equals
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;
}
}
但我认为下面的代码似乎效率更高
public boolean myEquals(Object o) {
if (o == this)
return true;
if (!(o instanceof Set))
return false;
Collection<?> c = (Collection<?>) o;
if (c.size() != this.size()) {
return false;
}
Iterator ic = c.iterator();
Iterator id = iterator();
while (ic.hasNext() && id.hasNext()) {
if (!ic.next().equals(id.next())) {
return false;
}
}
return true;
}
一个简单的测试也可能支持第二个equals
public class Test {
public static void main(String[] args) {
ConcurrentSkipListSet<Integer> set1 = new ConcurrentSkipListSet<Integer>();
ConcurrentSkipListSet<Integer> set2 = new ConcurrentSkipListSet<Integer>();
for (int i = 0; i < 10000000; i++) {
set1.add(i);
set2.add(i);
}
long ts = System.currentTimeMillis();
System.out.println(set1.equals(set2));
System.out.println(System.currentTimeMillis() - ts);
ts = System.currentTimeMillis();
System.out.println(myset1.myEquals(myset2));
System.out.println(System.currentTimeMillis() - ts);
}
}
输出结果
true
2713
true
589
在JDK评论中,This definition ensures that the equals method works properly across different implementations of the set interface.
任何人都可以解释一下吗?
答案 0 :(得分:0)
作为参考,OpenJDK thread导致创建JDK-8181146 ConcurrentSkipListSet.equals efficiency。
在JDK评论中,
This definition ensures that the equals method works properly across different implementations of the set interface.
任何人都可以解释一下吗?
它来自Set.equals(Object)。根据文件:
如果指定的对象也是一个集合,则返回true,两个集合具有相同的大小,并且指定集合的每个成员都包含在此集合中(或者等效地,此集合的每个成员都包含在指定的集合中) 。此定义确保equals方法在set接口的不同实现中正常工作。
这意味着Set.equals
实现应该由Set.contains(Object)的行为定义。然后,您将从java.util.SortedSet:
请注意,如果有序集合要正确实现Set接口,则由有序集合维护的排序(无论是否提供显式比较器)必须与equals一致。 (有关与equals一致的精确定义,请参阅Comparable接口或Comparator接口。)这是因为Set接口是根据equals操作定义的,但是有序集使用compareTo(或compare)方法执行所有元素比较因此,从排序集的角度来看,这种方法被认为相等的两个元素是相等的。即使排序与equals不一致,排序集的行为也是明确定义的;它只是不遵守Set接口的一般合同。
那么为什么&#39;这包含了这个&包含这个&#39;在ConcurrentSkipListSet
?首先,您要避免拨打ConcurrentSkipListSet.size(),因为:
请注意,与大多数集合不同,此方法不是恒定时间操作。由于这些集的异步性质,确定当前的元素数量需要遍历它们以计算它们。此外,在执行此方法期间可能会更改大小,在这种情况下返回的结果将是不准确的。因此,这种方法在并发应用程序中通常不是很有用。
第二个原因是你希望与等于&#39;。
保持一致让我们根据您的代码制作一个残酷的例子:
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
该输出显示新实现不是consistent with equals:
当且仅当e1.compareTo(e2)== 0与c1的每个e1和e2的e1.equals(e2)具有相同的布尔值时,C类的自然排序被认为与equals一致。请注意,null不是任何类的实例,并且即使e.equals(null)返回false,e.compareTo(null)也应抛出NullPointerException。
现在我们可以通过替换元素检查来解决这个问题
((Comparable) e1).compareTo((Comparable) e2) != 0
或Comparator.compare(e1, e2) != 0
并添加检查以尝试确定这两个集合使用相同的顺序,但请记住,集合可以被包装,并且没有任何内容可以阻止来自hiding the fact that a set is backed by sorted set的调用者。现在,您回到了包含该内容的内容,其中包含此内容。可以处理集合包装器的equals的实现。
&#39;的另一个不错的属性包含了这个包含这个&#39;实现是equals实现不是为给定的集合创建一个迭代器对象,在最坏的情况下可能会有一个像Arrays.asList(s.toArray()).iterator()
这样的实现。
不放松规范,放宽现有行为,或添加一个返回BiPredicate
的集合方法来捕捉等价关系&#39;对于集合,我认为很难向JDK添加这样的优化。