检查集合是否包含对象,按引用进行比较

Collection.contains()方法使用.equals() ()方法检查集合是否包含给定对象以执行比较。

来自Java7 Javadoc:

boolean contains(Object o)

如果此collection包含指定的元素,则返回true。 更正式地,当且仅当此集合包含至少一个元素e时才返回true(o == null?e == null:o.equals(e))。

有没有一种聪明的方法可以检查集合是否包含对象o ,而是通过引用进行比较(即o==e )?

当然我可以遍历集合并进行检查,我正在寻找可以做到这一点的现有function。

澄清:

  • 我想执行此操作, 无论集合中对象的equals()实现如何
  • 我不想更改集合中的对象或集合本身。

编辑:

即使我的问题是关于Collection实现的一般解决方案,也可以理解Collection子接口的特定情况。

对于我们这些使用Java 8的人来说, Collection#stream()是一个干净的选择:

 collection.stream().anyMatch(x -> x == key) 

有某种解决方法……

您可以使用IdentityHashMap ,将Void作为值(或其他任何 – 您的选择)。 然后,您可以在其.keySet() contains()上使用contains()来检查元素的存在(或直接在地图上显示.containsKey() )。

第二种解决方法是使用Guava和Equivalence.identity() ; 但是你的Collection必须有Equivalence.Wrapper类型的元素,你必须在检查前wrap


奇怪的是,JDK没有提供IdentityHashSet 。 考虑到HashSet的内部实现使用HashMap ,这是相当奇怪的,所以我们不得不想知道为什么他们不对IdentityHashMap做同样的事情……


附注: Collection的文档具有误导性; 并非所有Collection实现都依赖于.equals() 。 例如,请参阅SortedSetSortedMap 。 当然还有IdentityHashMap

无法检查您尝试的方式。 如果不迭代集合,则无法检查对象是否指向相同的引用。

AFAIK,否( 至少是干净的方式 )。

答案指出,不可能以干净的方式执行所需的检查。

所以这是这种请求函数的可能实现:

 /** * Returns {@code true} if the collection contains the specified element. * 

* More formally, returns {@code true} if and only if this collection * contains at least one element {@code x} such that {@code x == element}. *

* Note: {@link Collection#contains(Object)} works differently because uses * {@link Object#equals(Object)} for comparison * * @param collection * collection where to look for the element * @param element * element whose presence in this collection is to be tested * @return {@code true} if this collection contains the specified element * @throws NullPointerException * if {@code collection} is null */ public static boolean containsReferenceTo(Collection collection, T element) { if (collection == null) throw new NullPointerException("collection cannot be null"); for (T x : collection) { if (x == element) { return true; } } return false; }

注意:这可能针对某些特定的Collection实现进行了优化。

创建类时,应至少重写equals (和hashCode )方法。
如果您实施equals方法以通过引用进行比较,您将实现目标。

您应该能够通过将对象包装在您自己的对象中来实现,该对象实现了您正在寻找的equals

就像是:

 private class Identical { final T held; Identical (T hold) { held = hold; } public boolean equals(Object it) { return it != null && held == it; } } 

显然,您必须控制向集合中添加项目并将其中的每个项目包装在其中。

你可以像这样包装地图:

 static class ReferenceHashMap extends AbstractMap implements Map { private final Map> map = new HashMap<>(); private static class Identical { final T held; Identical(T hold) { held = hold; } @Override public boolean equals(Object it) { return it != null && held == it; } @Override public int hashCode() { return held.hashCode(); } } @Override public V get(Object key) { Identical value = map.get(key); return value == null ? null : value.held; } @Override public V put(K key, V value) { Identical replaced = map.put(key, new Identical<>(value)); return replaced == null ? null : replaced.held; } private class MyEntry implements Map.Entry { private final K key; private V value; public MyEntry(K key, V value) { this.key = key; this.value = value; } @Override public K getKey() { return key; } @Override public V getValue() { return value; } @Override public V setValue(V value) { V old = this.value; this.value = value; return old; } } @Override public Set> entrySet() { Set> entries = new HashSet<>(); for (Entry> entry : map.entrySet()) { entries.add(new MyEntry(entry.getKey(), entry.getValue().held)); } return entries; } }