Подтвердить что ты не робот

Проверьте, содержит ли коллекция объект, сравнивая по ссылке

Метод Collection.contains() проверяет, содержит ли коллекция данный объект, используя метод .equals() для выполнения сравнения.

Из Java7 Javadoc:

boolean содержит (Object o)

Возвращает true, если эта коллекция содержит указанный элемент. Более формально возвращает true тогда и только тогда, когда коллекция содержит хотя бы один элемент e такой, что (o == null? e == null: o.equals(e)).

Есть ли разумный способ проверить, содержит ли коллекция объект o, но вместо сравнения вместо него (т.е. o==e)?

Конечно, я могу перебирать коллекцию и делать чек, я ищу существующую функцию, которая может это сделать.

Разъяснения:

  • Я хочу выполнить эту операцию независимо от реализации объекта equals() объекта в коллекции.
  • Я не хочу менять объекты в коллекции и сам сбор.

Edit:

Несмотря на то, что мой вопрос касается общего решения для реализаций Collection, также будут оценены конкретные случаи для суб-интерфейсов Collection.

4b9b3361

Ответ 1

Для тех из нас, кто использует Java 8, Collection#stream() - это чистая опция:

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

Ответ 2

Существует какое-то обходное решение...

Вы можете использовать IdentityHashMap, а Void - как значения (или что-то еще - ваш выбор). Затем вы использовали contains() на .keySet(), чтобы проверить наличие элемента (или .containsKey() на карте напрямую).

Вторым обходным решением будет использование Guava и Equivalence.identity(); однако ваш Collection должен иметь элементы типа Equivalence.Wrapper<X>, и вам нужно будет wrap перед проверкой...


Любопытно, что JDK не предоставляет IdentityHashSet. Это довольно странно, учитывая, что внутренняя реализация HashSet использует HashMap, поэтому нужно задаться вопросом, почему они не сделали то же самое для IdentityHashMap...


Боковое примечание: документация Collection вводит в заблуждение; не все реализации Collection полагаются на .equals(). См., Например, SortedSet или SortedMap. И, конечно, IdentityHashMap.

Ответ 3

Нет способа проверить, что вы пытаетесь сделать. Без повторения с помощью коллекции вы не можете проверить, что объект указывает на ту же ссылку или нет.

AFAIK, Нет (по крайней мере, чистый путь).

Ответ 4

В ответах указывается, что невозможно выполнить желаемую проверку.

Итак, это возможная реализация такой запрошенной функции:

/**
 * 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.

Ответ 5

При создании класса вы должны переопределить методы equalshashCode). Если вы реализуете свой метод equals для сравнения по ссылке, вы достигнете своей цели.

Ответ 6

Вы можете сделать это, обернув объект в свой собственный объект, который реализует 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;
    }

}