Wie wertet die Methode include () einer ArrayList Objekte aus?

303

Angenommen, ich erstelle ein Objekt und füge es meinem hinzu ArrayList. Wenn ich dann ein anderes Objekt mit genau derselben Konstruktoreingabe erstelle, contains()bewertet die Methode die beiden Objekte als gleich? Angenommen, der Konstruktor macht mit der Eingabe nichts Lustiges und die in beiden Objekten gespeicherten Variablen sind identisch.

ArrayList<Thing> basket = new ArrayList<Thing>();  
Thing thing = new Thing(100);  
basket.add(thing);  
Thing another = new Thing(100);  
basket.contains(another); // true or false?

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

Soll das classso umgesetzt werden, um eine contains()Rückkehr zu haben true?

Mantas Vidutis
quelle

Antworten:

339

ArrayList implementsdie Listenschnittstelle.

Wenn Sie sich das Javadoc fürList die containsMethode ansehen, werden Sie feststellen, dass es die equals()Methode verwendet, um zu bewerten, ob zwei Objekte gleich sind.

Binärer Nerd
quelle
61
Nur für den Fall, dass Sie equals () überschreiben möchten, stellen Sie sicher, dass Sie auch die Methode hashcode () überschreiben. Wenn Sie dies nicht tun, funktionieren die Dinge möglicherweise nicht wie erwartet, wenn Sie Sammlungen verwenden?
Mohd Farid
34
Dies ist eine korrekte Antwort. Beachten Sie jedoch, dass Sie die Methode equals ändern müssen, um eine Objectstatt einer zu akzeptieren Thing. Wenn Sie dies nicht tun, wird Ihre Methode equals nicht verwendet. :)
Mdierker
1
Ich habe gerade für mich entdeckt, dass Eclipse im Menü "Quelle" den Befehl "Hashcode generieren () und gleich" hat.
Volodymyr Krupach
Dies beantwortet die Frage im Titel, aber nicht die Frage in der Beschreibung, dh "Wenn ich dann ein anderes Objekt mit genau derselben Konstruktoreingabe erstelle, wertet die Methode includes () die beiden Objekte als gleich aus?"
Robguinness
3
CollectionsMachen Sie ihre Sachen auf optimierte Weise, was bedeutet, dass contains()zuerst das hashCodes der beiden Objekte überprüft wird und erst dann aufgerufen wird equals(). Wenn die hashCodes unterschiedlich sind (was bei zwei verschiedenen Instanzen von immer der Fall ist Thing), wird die equals()Methode nicht aufgerufen. Als Faustregel gilt, dass Sie beim Überschreiben equals()nicht vergessen sollten, auch zu überschreiben hashCode().
Sevastyan Savanyuk
52

Ich denke, dass richtige Implementierungen sein sollten

public class Thing
{
    public int value;  

    public Thing (int x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}
ChristopheCVB
quelle
1
ifAussage ist unnötig. instanceofreicht.
Paul
@ Paul, über welchen Teil der Aussage sprichst du?
ChristopheCVB
4
Die object != nullBedingung ist nicht erforderlich, da object instanceof Thingüberprüft wird, ob das Objekt auch nicht null ist.
Alexander Farber
15

Die ArrayList verwendet die in der Klasse implementierte equals-Methode (Ihre case Thing-Klasse), um den equals-Vergleich durchzuführen.

Bhushan Bhangale
quelle
12

Im Allgemeinen sollten Sie bei hashCode()jedem Überschreiben equals()auch überschreiben , auch wenn dies nur zur Leistungssteigerung dient. HashCode()entscheidet, in welchen 'Bucket' Ihr Objekt beim Vergleich sortiert wird. equal()Daher sollten zwei beliebige Objekte, die als true ausgewertet werden, dasselbe zurückgeben hashCode value(). Ich kann mich nicht an das Standardverhalten von erinnern hashCode()(wenn es 0 zurückgibt, sollte Ihr Code nur langsam funktionieren, aber wenn es die Adresse zurückgibt, schlägt Ihr Code fehl). Ich erinnere mich an einige Male, als mein Code fehlgeschlagen ist, weil ich vergessen habe, ihn zu überschreiben hashCode(). :) :)

alexloh
quelle
7

Es verwendet die equals-Methode für die Objekte. Wenn Thing nicht gleich überschreibt und die in den Objekten gespeicherten Variablen zum Vergleich verwendet, wird für die contains()Methode kein true zurückgegeben .

Yishai
quelle
6
class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    equals (Thing x) {
        if (x.value == value) return true;
        return false;
    }
}

Sie müssen schreiben:

class Thing {  
    public int value;  

    public Thing (int x) {
        value = x;
    }

    public boolean equals (Object o) {
    Thing x = (Thing) o;
        if (x.value == value) return true;
        return false;
    }
}

Jetzt gehts ;)

Davide
quelle
6
du solltest nicht tun Sache x = (Sache) o; ohne vorher zu prüfen, ob das andere Objekt null ist
Stahlhai
5

Ich wollte nur beachten, dass die folgende Implementierung falsch ist, wenn valuees sich nicht um einen primitiven Typ handelt:

public class Thing
{
    public Object value;  

    public Thing (Object x)
    {
        this.value = x;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean sameSame = false;

        if (object != null && object instanceof Thing)
        {
            sameSame = this.value == ((Thing) object).value;
        }

        return sameSame;
    }
}

In diesem Fall schlage ich Folgendes vor:

public class Thing {
    public Object value;  

    public Thing (Object x) {
        value = x;
    }

    @Override
    public boolean equals(Object object) {

        if (object != null && object instanceof Thing) {
            Thing thing = (Thing) object;
            if (value == null) {
                return (thing.value == null);
            }
            else {
                return value.equals(thing.value);
            }
        }

        return false;
    }
}
Caner
quelle
Wie kann man dies implementieren und gleichzeitig das Duplikat entfernen?
Sujay
4

Andere Poster haben sich mit der Frage befasst, wie enthält () funktioniert.

Ein ebenso wichtiger Aspekt Ihrer Frage ist die ordnungsgemäße Implementierung von equals (). Und die Antwort darauf hängt wirklich davon ab, was Objektgleichheit für diese bestimmte Klasse ausmacht. Wenn Sie in dem von Ihnen angegebenen Beispiel zwei verschiedene Objekte haben, die beide x = 5 haben, sind sie gleich? Es hängt wirklich davon ab, was Sie versuchen zu tun.

Wenn Sie nur an Objektgleichheit interessiert sind, verwendet die Standardimplementierung von .equals () (die von Object bereitgestellte) nur die Identität (dh this == other). Wenn Sie dies möchten, implementieren Sie equals () einfach nicht in Ihre Klasse (lassen Sie sie von Object erben). Der von Ihnen geschriebene Code ist zwar korrekt, wenn Sie sich für eine Identität entscheiden, wird jedoch niemals in einer realen Klasse b / c angezeigt. Er bietet keinen Vorteil gegenüber der Verwendung der Standardimplementierung von Object.equals ().

Wenn Sie gerade erst mit diesem Zeug anfangen, empfehle ich dringend das Effective Java-Buch von Joshua Bloch. Es ist eine großartige Lektüre und behandelt diese Art von Dingen (und wie man equals () korrekt implementiert, wenn Sie versuchen, mehr als nur identitätsbasierte Vergleiche durchzuführen).

Kevin Day
quelle
Zu meinem Zweck habe ich versucht zu sehen, ob sich ein gleichwertiges Objekt in der ArrayList befindet. Ich nehme an, es ist eine Art Hack. Vielen Dank für die Buchempfehlung
Mantas Vidutis
3

Verknüpfung von JavaDoc :

Boolescher Wert enthält (Objekt o)

Gibt true zurück, wenn diese Liste das angegebene Element enthält. Genauer gesagt, gibt true genau dann zurück, wenn diese Liste mindestens ein Element e enthält, so dass (o == null? E == null: o.equals (e))

DenisKolodin
quelle