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

时间:2014-03-21 11:07:03

标签: java collections

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

来自Java7 Javadoc:

  

布尔包含(对象o)

     

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

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

当然,我可以遍历整个系列并进行检查,我正在寻找能够做到这一点的现有功能。

澄清:

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

修改

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

6 个答案:

答案 0 :(得分:32)

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

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

答案 1 :(得分:10)

有某种解决方法......

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

第二种解决方法是使用Guava和Equivalence.identity();但是,您的Collection必须包含Equivalence.Wrapper<X>类型的元素,并且在检查之前您必须wrap ...


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


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

答案 2 :(得分:3)

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

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

答案 3 :(得分:3)

答案指出无法以干净的方式执行所需的检查。

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

/**
 * Returns {@code true} if the collection contains the specified element.
 * <p>
 * More formally, returns {@code true} if and only if this collection
 * contains at least one element {@code x} such that {@code x == element}.
 * <p>
 * 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 <T> boolean containsReferenceTo(Collection<T> 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实现进行优化。

答案 4 :(得分:2)

创建课程时,您应该至少覆盖equals(和hashCode)方法 如果您通过引用实施equals方法进行比较,那么您将实现目标。

答案 5 :(得分:0)

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

类似的东西:

private class Identical<T> {
    final T held;

    Identical (T hold) {
        held = hold;
    }

    public boolean equals(Object it) {
        return it != null && held == it;
    }
}

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

你可以像这样包装地图:

static class ReferenceHashMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {

    private final Map<K, Identical<V>> map = new HashMap<>();

    private static class Identical<T> {

        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<V> value = map.get(key);
        return value == null ? null : value.held;
    }

    @Override
    public V put(K key, V value) {
        Identical<V> replaced = map.put(key, new Identical<>(value));
        return replaced == null ? null : replaced.held;
    }

    private class MyEntry implements Map.Entry<K, V> {

        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<Entry<K, V>> entrySet() {
        Set<Entry<K, V>> entries = new HashSet<>();
        for (Entry<K, Identical<V>> entry : map.entrySet()) {
            entries.add(new MyEntry(entry.getKey(), entry.getValue().held));
        }
        return entries;
    }

}