Какой метод Set.removeAll () использует ниже: равно или сравнить? - PullRequest
4 голосов
/ 12 мая 2009

Рассмотрим код:

class A {

  private int i;

  boolean equals( Object t) {
      if (this == t)
          return true;
      if (!( t instanceof A))
          return false;
      if (this.i == t.i);
  }

}

Map<String,A> orig;
Map<String,B> dup;

Я пытаюсь сделать это

orig.entrySet().removeAll(dup.entrySet());

Я вижу, что вызывается метод equals; всегда ли это так, или вместо этого может вызываться сравнение?

Ответы [ 7 ]

4 голосов
/ 12 мая 2009

Да, звонит equals(). compareTo() можно использовать, только если Set знал , что в нем содержится Comparable объектов (например, отсортированные наборы могут это делать).

3 голосов
/ 12 мая 2009

Зависит от реализации.

Например, HashSet будет использовать hashCode и equals. A TreeSet, вероятно, будет использовать compareTo. В конечном счете, пока ваши типы ведут себя должным образом, это не должно иметь значения.

1 голос
/ 08 июля 2009

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collection.html

"Реализации свободны для реализации оптимизаций, благодаря которым избегается равный вызов, например, сначала сравнивая хэш-коды двух элементов."

Скорее всего, будет использоваться equals, но, учитывая приведенное выше утверждение, вы не можете полностью полагаться на equals () для вызова. Помните, что всегда полезно переопределять hashCode () всякий раз, когда вы переопределяете equals ().

1 голос
/ 12 мая 2009

TreeSet использует сравнение, попробуйте это:

public class A {

    private int i;

    A(int i) {
        this.i = i;
    }

    @Override
    public boolean equals(Object t) {
        if (this == t)
            return true;
        if (!( t instanceof A))
            return false;
        return (this.i == ((A)t).i);
    }

    public static void main(String[] args) {
        List<A> remove = Arrays.asList(new A(123), new A(789));
        Set<A> set = new TreeSet<A>(new Comparator<A>() {
            @Override
            public int compare(A o1, A o2) {
                return o1.i - o2.i;  
                // return 0; // everything get removed
            }
        });
        set.add(new A(123));
        set.add(new A(456));
        set.add(new A(789));
        set.add(new A(999));

        set.removeAll(remove);
        for (A a : set) {
            System.out.println(a.i);
        }
        System.out.println("done");
    }
}

заставить компаратор всегда возвращать 0 и все будет удалено! То же самое происходит, если вы не используете Comparator, а используете Comparable.

TreeSet основан на TreeMap, который использует сравнение в getEntry.
В Javadoc TreeSet вы можете (наконец) прочитать:

... интерфейс Set определяется в терминах операции equals, но экземпляр TreeSet выполняет все сравнения элементов, используя свой метод CompareTo (или сравнение) ...

[]]

0 голосов
/ 12 мая 2009

Я не вижу, где используется CompareTo; javadoc для remove () для интерфейса Map говорит: «Более формально, если эта карта содержит отображение ключа k на значение v, такое что (key == null? k == null: key.equals (k)) это отображение устранен." В то время как для интерфейса Set он аналогично говорит: «Более формально, удаляет элемент e такой, что (o == null? E == null: o.equals (e)), если набор содержит такой элемент."

Обратите внимание, что в javadoc removeAll () не сказано, как он работает, а это означает, что, как говорили другие, это деталь реализации.

В Sun Java, согласно Блоху в его «Эффективной Java» (если я правильно помню), он перебирает коллекцию и вызывает метод remove (), но он подчеркивает, что вы никогда не должны предполагать, что это всегда так.

0 голосов
/ 12 мая 2009

Единственная реализация в библиотеке Java, о которой я знаю, что это не сделает, - это IdentityHashMap . TreeMap , например, не имеет соответствующего Comparator.

0 голосов
/ 12 мая 2009

Некоторые реализации Set полагаются на hashCode (например, HashSet). Вот почему вы всегда должны переопределять hashCode также, когда переопределяете equals.

...