2009-05-12 4 views
3

Betrachten Sie den Code:Welche Methode verwendet Set.removeAll() darunter: gleich oder 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; 

ich diesen

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

ich, dass die Methode equals sehen zu tun versuchen heißt; ist das immer wahr, oder kann man stattdessen compareTo aufrufen?

+2

Set ist eine Schnittstelle. Das Verhalten removeAll hängt von der Implementierung ab. Ich glaube, dass HashSet equals verwendet, während TreeSet compare oder compareTo verwendet. –

+1

nur eine kleine Anmerkung: die letzte Zeile Ihres Gleichen ist nicht korrekt (nur ein NOP). Wahrscheinlich wolltest du so etwas wie: "return this.i == ((A) t) .i;" –

Antwort

3

Ja, es ruft equals(). compareTo() könnte nur verwendet werden, wenn die Setwüsste, dass es Comparable Objekte (sortierte Mengen, könnte dies möglicherweise tun).

+0

Ich meinte, es ist nur gleich oder es sieht compareTo usw. und ich muss diese für Klasse A sowie – kal

+0

implementieren ich sehe. Ich habe meine Antwort geändert und Sie möchten vielleicht die Frage ändern, um dies deutlicher zu formulieren. –

+0

Es ist der Eintrag in der Karte. Event für eine TreeMap würde es nicht wissen, dass der Inhalt vergleichbar ist. –

3

Es hängt von der Implementierung ab.

Zum Beispiel wird ein HashSet und equals verwenden. A TreeSet wird wahrscheinlich compareTo verwenden. Solange sich Ihre Typen angemessen verhalten, sollte das keine Rolle spielen.

+0

Dies ist für den Wert auf dem Eintrag gesetzt, so dass TreeMap nicht einen geeigneten Copmarator haben wird und der Wert ist nicht unbedingt (und in diesem Fall nicht) vergleichbar. –

+0

Tom: Wenn ich durch den Code schaue, sieht es für mich sicher so aus, als ob compareTo für den Schlüssel verwendet wird, und dann Gleichheit für den Wert. –

0

Einige Set Implementierungen beruhen auf hashCode (z. B. HashSet). Deshalb sollten Sie auch hashCode immer überschreiben, wenn Sie equals überschreiben.

+0

Sie sollten in der Tat HashCode überschreiben, aber HashSet ruft auch gleich(), nur um sicher zu sein. –

+0

mmeyers: Wenn zwei equals-Objekte nicht genau den gleichen hashCode haben (weil sie ihn zum Beispiel nicht überschreiben), dann dürfen sie niemals equals haben. Auch wenn sie denselben hashCode haben, gibt es keinen Grund, warum Objekte gleich sein sollten. –

+0

Ja; Ich war mir nicht sicher, ob die Frage war "Muss ich Gleichgestellte außer Kraft setzen?" oder "ist gleich der einzigen Methode, die ich überschreiben muss?" –

0

Die einzige Implementierung innerhalb der Java-Bibliothek, von der ich weiß, dass sie dies nicht tut, ist IdentityHashMap. TreeMap zum Beispiel hat keine passende Comparator.

0

Ich sehe nicht, wo compareTo verwendet wird; Das Javadoc für remove() für die Map-Schnittstelle sagt "Formaler, wenn diese Map eine Zuordnung von Schlüssel k zu Wert v enthält, so dass (key == null? k == null: key.equals (k)), diese Zuordnung ist entfernt." Während für die Set-Schnittstelle sagt es ähnlich "Formaler entfernt ein Element e so, dass (o == null? E == null: o.equals (e)), wenn die Menge ein solches Element enthält."

Beachten Sie, dass javadoc removeAll() nicht sagt, wie es funktioniert, was bedeutet, wie andere gesagt haben, dass es ein Implementierungsdetail ist. In Suns Java, so Bloch in seinem Effektiven Java (wenn ich mich recht erinnere), iteriert es über die Sammlung und ruft remove() auf, aber er betont, dass man niemals davon ausgehen darf, dass es so immer gemacht wird.

1

Die TreeSet die compareTo verwendet, versuchen Sie dies:

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"); 
    } 
} 

der Komparator immer 0 und alles machen zurückkehren entfernt werden! Gleiches passiert, wenn kein Komparator verwendet wird, aber Comparable implementiert wird.

Das TreeSet basiert auf einer TreeMap, die das compareTo in getEntry verwendet.
In der Javadoc der TreeSet können Sie (endlich) lesen:

... die Set-Schnittstelle in Bezug auf die Gleichgestellten Betrieb definiert ist, sondern eine TreeSet Instanz führt alle Element Vergleiche seine compareTo mit (oder vergleichen) Methode ...

[]]

1

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

"Implementationen sind frei Optimierungen zu implementieren, wobei das Gleichheits Invokation vermieden wird, zum Beispiel, indem zuerst die Hash-Codes der beiden Elemente zu vergleichen."

Wahrscheinlich wird gleich verwendet, aber unter Berücksichtigung der obigen Aussage können Sie sich nicht vollständig darauf verlassen, dass equals() aufgerufen wird. Denken Sie daran, dass es immer eine gute Idee ist, hashCode() zu überschreiben, wenn Sie equals() überschreiben.