2009-05-12 1 views
3

Рассмотрим код:Какой метод использует Set.removeAll() для использования ниже: equals или compareTo?

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()); 

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

+2

Set - это интерфейс. Поведение removeAll зависит от реализации. Я считаю, что HashSet использует equals, а TreeSet использует compare или compareTo. –

+1

всего лишь небольшая заметка: последняя строка ваших равных неверна (просто NOP). Вероятно, вам нужно что-то вроде: "return this.i == ((A) t) .i;" –

ответ

3

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

+0

Я имел в виду, что он только равен или он смотрит на compareTo и т. Д., И мне нужно реализовать те же, что и для класса А – kal

+0

. Я изменил свой ответ, и вы, возможно, захотите изменить вопрос, чтобы более четко прописать это. –

+0

Это набор карт. Событие для TreeMap не будет знать, что содержимое сопоставимо. –

3

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

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

+0

Это значение для набора записей, поэтому у TreeMap не будет подходящего Copmarator, и значение не обязательно (и не в этом случае). –

+0

Том: Просматривая код, он, безусловно, выглядит так, как если бы он использовал compareTo для ключа, а затем равенство для значения. –

0

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

+0

Вы действительно должны переопределить hashCode, но HashSet также вызывает equals() только для того, чтобы быть в безопасности. –

+0

mmeyers: Если два объекта равны не точно одинаковому хэш-коду (потому что они не переопределяют его, например), то они, возможно, никогда не имеют равных, вызываемых на них. Аналогично, даже если они имеют одинаковый хэш-код, нет причин, по которым объекты должны быть равными. –

+0

Да; Я не был уверен, был ли вопрос «нужно ли мне переопределять равные?» или "является единственным методом, который мне нужно переопределить?" –

0

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

0

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

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

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

1

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, и все будут удалены! То же самое происходит, если не использовать Компаратор, а реализовать Comparable.

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

... интерфейс Set определен в терминах операции РАВНО, но экземпляр TreeSet выполняет все сравнения элементов, используя его СотрагеТо (или сравнить) метод ...

[]]

1

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

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

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

Смежные вопросы