2016-03-24 12 views
15

Ist es möglich, Object#equals(Object) lokal zu überschreiben, wenn list.contains(someObject) verwendet wird?Überschreibendes Objekt # ist gleich (Objekt) außerhalb der Klasse

Beispiel:

class SomeObject { 
    ... 
    private int id; 
    private String name; 

    @Overrdide 
    public boolean equals(Object other){ 
     ... 
     return this.id == other.id; 
    } 
} 

Aber was, wenn ich eine andere Art von Gleichen will, wenn ich list.contains(someObject) verwenden? Zum Beispiel möchte ich wissen, ob eine Liste einen bestimmten Namen enthält? Ist es möglich, Object#equals(Object) 'anonym' zu überschreiben?

Speziellere Erklärung, warum ich es brauchen würde:

int objectId = ... // Some event which passes me the attribute of an object but not the object itself 

Jetzt habe ich List<SomeObject> someObjects und ich würde gerne wissen, ob diese Liste ein Objekt mit objectId enthält, ohne notwendigerweise über sie iterieren.

One „Lösung“ Ich könnte denken würde Map<Integer, SomeObject> mapping verwenden und dann someObject = mapping.get(objectId)

EDIT: Meine Frage ist kein Duplikat, da ich speziell Object#equals(Object) außer Kraft zu setzen bin zu fragen.

+0

Es sollte sein, aber das ist IMHO das Schlimmste an der Sammlung API. Sie können einen benutzerdefinierten Vergleicher an vielen Stellen verwenden, aber Sie sind mit nur einer Vorstellung von 'equals' festgefahren. –

+1

Wenn Java nur Fallklassen hatte :-( – SklogW

+0

Die Verwendung eines Vergleichers zur Angabe der Gleichheit funktioniert für einen Satz und für Map-Schlüssel (aber es beeinträchtigt die Leistung - Operationen werden zu O (log n), weil Sie TreeMap anstelle von HashMap verwenden müssen). Es hilft jedoch nicht mit List.Es könnte möglich sein, einen benutzerdefinierten Begriff der Gleichheit mit Methoden wie 'indexOf',' contains' usw. zu verwenden, aber es ist nicht möglich, ohne eine Wrapper-Klasse zu erstellen und gleich zu überschreiben, wie Sie wollen ärgerlich. –

Antwort

16

Sie können einen Filter auf ein Stream-Objekt anwenden, das Sie aus der Liste erhalten haben. Der Filter verwendet ein Prädikat, in dem Sie die Bedingung festlegen können. Dann können Sie überprüfen, ob der gefilterte Strom nicht leer ist:

list.stream().filter(e -> e.name.equals(otherName)).findAny().isPresent() 

Sie können es wiederverwendbar machen beispielsweise wie folgt:

private <T> boolean containsWithPredicate(List<T> list, Predicate<T> predicate) { 
    return list.stream().filter(predicate).findAny().isPresent(); 
} 

und es nennen wie folgt:

boolean containsElement = containsWithPredicate(myListOfObjects, 
               (e -> e.name.equals(otherName))); 

EDIT:

Es gibt eine viel einfachere Art und Weise zu tun genau das gleiche oben nur Stream.anyMatch Aufruf anstatt das zu tun filter dann findAny:

list.stream().anyMatch(predicate); 
+7

Nicht sicher, ob es eine Lösung oder eine Problemumgehung ist, da ich auch mit einer for-each-Schleife iterieren konnte. Aber es ist definitiv ein Ansatz. – SklogW

+2

@SklogW Ich denke, es ist eine Lösung. Eine anonyme "' equals "" - Methode wird benötigt, die angepasst werden kann, so dass man zuerst an die funktionale Stilprogrammierung denkt (Sie können das Prädikat des Filters als Argument übergeben). Es scheint auch einfacher zu lesen. – manouti

+2

@SklogW Das möchten Sie eigentlich machen. Sie möchten keine neue 'equals'-Methode erstellen. Sie möchten überprüfen, ob Listen bestimmte Elemente enthalten, und Sie möchten ein [' Prädikat'] (https://docs.oracle.com /javase/8/docs/api/java/util/function/Predicate.html) - was genau das Lambda im [Filter] ist (https://docs.oracle.com/javase/8/docs) /api/java/util/stream/Stream.html#filter-java.util.function.Predicate-) Methode ist. –

7

Sie Comparator ein TreeSet mit einem benutzerdefinierten verwenden kann, um zu erreichen, was Sie wollen. Es verwendet equals() nicht für die Gleichheit, sondern berücksichtigt, dass, wenn compare()0 zurückgibt, Objekte gleich sind.

Lassen Sie uns sagen, dass wir wollen, dass alle Strings gleich sein, wenn sie die gleiche Länge:

TreeSet<String> set = new TreeSet(new Comparator<>() { 
    public int compare(String o1, String o2) { 
     return o1.length() - o2.length(); 
    } 
} 
set.add("asd"); 
set.contains("foo"); // Returns true 

Dies kann ein nützliches Konstrukt sein (funktioniert mit TreeMap auch) in Fällen, in denen Sie verschiedene „Gleichheit haben müssen Definitionen "für Objekte zu verschiedenen Zeiten, während noch mit Sammlungen arbeiten.

+0

Aber es gibt mir immer noch eine Liste mit einer dauerhaften Definition dessen, was gleich ist oder nicht, oder? Was ist, wenn ich eine bestimmte Art von Gleichen nur einmal möchte? Kann ich zum Beispiel den Komparator ändern? – SklogW

+1

Es wird definiert "was gleich ist" für diese Sammlung. Sie könnten den Komparator so schreiben, dass er für verschiedene Objekte unterschiedliche Logik hat, aber er wird fehleranfälliger und Sie müssen sicherstellen, dass Sie sich an den Vertrag von compare() halten. – Kayaman

6

Es gibt keine Möglichkeit, mehrere equals für die gleiche Klasse zu haben.Aber Sie können Unterklasse Ihre Klasse und überschreiben hashCode() und equals(), dann verwenden Sie die gewünschte Instanz je nach der equals Sie verwenden möchten.

Ich muss sagen, dass ich nicht gerne das tun, sollte die equals Methode gut definiert sein, wird es sehr verwirrend sein, mehrere equals auf verschiedenen Szenarien zu verwenden. Statt Subclassing hätte ich völlig unterschiedliche Implementierungen, wenn ich zwei verschiedene equals Methoden hätte. Ich rate Ihnen daher dringend, Ihr Design zu überdenken.

+3

Guter Rat. Wenn ich verschiedene Gleichheiten brauche, dann ist vielleicht mein Design das Problem. Ich werde darüber nachdenken. – SklogW

+1

@SklogW Es ist eine gute Idee. Denken Sie an andere Programmierer, die Ihr Programm verwenden könnten, wie werden sie wissen, welche Implementierung zu wählen? 'equals' sollte wirklich gut definiert sein. – Maroun

+0

Es macht Sinn. Ich denke, ich versuche, ein schlechtes Design zu umgehen. Danke ! – SklogW

Verwandte Themen