In einem Set doppelte Elemente erzeugen

jCoder1984

Aktives Mitglied
Hallo zusammen ich mal eine theoretische Frage :
Wenn ich eine einfache Klasse habe, die zwei String values hat.

Java:
public class Test {
    private String value1;
    private String value2;

    public Test(String value1, String value2) {
        this.value1 = value1;
        this.value2 = value2;
    }

    public void setValue1(String value1) {
        this.value1 = value1;
    }

    public void setValue2(String value2) {
        this.value2 = value2;
    }

    @Override
    public boolean equals(Object obj) {
        return ((Test) obj).value1.equals(value1) && ((Test) obj).value2.equals(value2);
    }
}

Entscheidend die Equals Funktion.
Wenn ich nun einen Set habe und einen Instanz dieser Klasse einfüge :

Java:
        Set<Test> testSet = new HashSet<>();
        Test test1 = new Test("testValue1", "testValue2");
        Test test2 = new Test("testValue12", "testValue22");
       
        testSet.add(test1);
        testSet.add(test2);
       
        test2.setValue1("testValue1");
        test2.setValue2("testValue2");

Wie ihr seht, werden zwei unterschiedlich Objekte erzeugt und in einer HashSet eingefügt.
NUn wird aber test2 so verändert, dass es die gleichen Values hat wie test1. Nun meine Frage gibt es nun 2 gleiche Elemente in der HashSet oder nicht. Was ist eure Meinung bzw. kann mir jemand einen Tipp geben wo der Denkfehler liegt.

Vielen vielen Dank
 
Hallo,

wenn man die equals & hashcode Methode richtig implementiert dann wären das jetzt zwei identische Objekte im Set obwohl beide zwei unterschiedliche Referenzen besitzen.

Deine Equals Methode kann auch ein NPE verursachen 🙂

Besser:

Java:
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;

    if (obj == null)
        return false;

    if (getClass() != obj.getClass())
        return false;

    Test other = (Test) obj;

    if (value1 == null) {

        if (other.value1 != null)
            return false;

    } else if (!value1.equals(other.value1))
        return false;

    if (value2 == null) {

        if (other.value2 != null)
            return false;

    } else if (!value2.equals(other.value2))
        return false;

    return true;
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((value1 == null) ? 0 : value1.hashCode());
    result = prime * result + ((value2 == null) ? 0 : value2.hashCode());
    return result;
}

Zu Hashcode:
Die Methode hashCode() soll zu jedem Objekt eine möglichst eindeutige Integerzahl (sowohl positiv als auch negativ) liefern, die das Objekt identifiziert. Die Ganzzahl heißt Hashcode beziehungsweise Hash-Wert, und hashCode() ist die Implementierung einer Hash-Funktion. Nötig sind Hashcodes, wenn die Objekte in speziellen Datenstrukturen untergebracht werden, die nach dem Hashing-Verfahren arbeiten. Datenstrukturen mit Hashing-Algorithmen bieten einen effizienten Zugriff auf ihre Elemente. Die Klasse java.util.HashMap z. B implementiert eine solche Datenstruktur.


Ein Auszug aus Java Galileo:

Java:
Player bruceWants = new Player();
bruceWants.name = "Bruce Wants";
bruceWants.age = 32;
bruceWants.weight = 70.3;

Player bruceLii = new Player();
bruceLii.name = "Bruce Lii";
bruceLii.age = 32;
bruceLii.weight = 70.3;;

System.out.println( bruceWants.hashCode() );                 // –340931147
System.out.println( bruceLii.hashCode() );                   // 301931244
System.out.println( System.identityHashCode( bruceWants ) ); // 1671711
System.out.println( System.identityHashCode( bruceLii ) );   // 11394033
System.out.println( bruceLii.equals( bruceWants ) );         // false

bruceWants.name = "Bruce Lii";
System.out.println( bruceWants.hashCode() );                 // 301931244
System.out.println( bruceLii.equals( bruceWants ) );         // true

Beim ändern eines Wertes solltest du auch sicherstellen, dass diese evtl. entfernt werden muss aus der Datenstruktur.

Grüße
 
Zuletzt bearbeitet:
HashSet, wie der Name schon sagt, benutzt den Hash eines Objektes (hashCode()), den du nicht überschreibst. Wenn 2 Objekte den selben HashCode besitzen wird auf die euqals-Methode zurückgegriffen und wenn beide unterschiedlich sind, werden sie als Linked List abgelget. Soviel zur Implementierung von HashSet.

Einzigartigkeit kann ein Set nur beim Einfügen garantiern. Wenn sich der interne Zustand eines Objektes ändert - somit hashCode & equals - bekommt das Set das nicht mit (keine Standardimplementierung kann das) - auch wird die HashTable intern nicht neu organisiert. Somit hast du auch noch ein MemoryLeak, da das Objekt nicht vom Garbagecollector gefressen wird. Also Merke:
Wenn du ein Objekt änderst, dass in einem Set vorhanden ist: Objekt aus Set löschen, Objekt ändern und Objekt neu einfügen.

Also zurück zu deiner Frage: Du hast zwei Objekte in deinem Set (kann man leicht überprüfen mit Set.size()), mit Constraintviolation für Sets - die du selbst verursacht hast.
 
Einzigartigkeit kann ein Set nur beim Einfügen garantiern. Wenn sich der interne Zustand eines Objektes ändert - somit hashCode & equals - bekommt das Set das nicht mit (keine Standardimplementierung kann das) - auch wird die HashTable intern nicht neu organisiert. Somit hast du auch noch ein MemoryLeak, da das Objekt nicht vom Garbagecollector gefressen wird. Also Merke:
Wenn du ein Objekt änderst, dass in einem Set vorhanden ist: Objekt aus Set löschen, Objekt ändern und Objekt neu einfügen.

Also zurück zu deiner Frage: Du hast zwei Objekte in deinem Set (kann man leicht überprüfen mit Set.size()), mit Constraintviolation für Sets - die du selbst verursacht hast.

Flown war schneller 🙂 Das wollte ich eben auch anmerken. Die Prüfung findet nur beim Hinzufügen eines weiteren Objekts statt. Ist das Objekt mal im Set findet keine weitere Prüfung auf Gleichheit statt.
 
Aber solche Fragen können leicht in der Dokumentation HIER nachgelesen werden:
Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set. A special case of this prohibition is that it is not permissible for a set to contain itself as an element.
 

Zurück
Oben