Spaß mit Mutable

Ich habe neulich ein lustiges Problem in einem Programmcode gefunden. Runtergebrochen und stark vereinfacht sah das Problem so aus:

package mutable;

import java.util.HashSet;
import java.util.Set;

public class Mutable {

    static class MyEntity {

        String name;

        public MyEntity(String s) {
            name = s;
        }

        public String getName() {
            return name;
        }

        public void setName(String s) {
            name = s;
        }

        @Override
        public int hashCode() {
            return name.hashCode();
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final MyEntity other = (MyEntity) obj;
            if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
                return false;
            }
            return true;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    public static void main(String[] args) {
        MyEntity hund = new MyEntity("Hund");
        MyEntity katze = new MyEntity("Katze");
        MyEntity maus = new MyEntity("Maus");

        Set<MyEntity> tiere = new HashSet<MyEntity>();
        tiere.add(hund);
        tiere.add(katze);
        tiere.add(maus);

        testSetFor(tiere, maus);
        System.out.println("---------------");
        maus.setName("Haus");
        testSetFor(tiere, maus);
    }

    private static void testSetFor(Set<MyEntity> set, MyEntity entry) {
        if (set.contains(entry)) {
            System.out.println("Is da!");
        } else {
            System.out.println("Nixn, kein '" + entry + "' in tiere!");
        }

        System.out.println("Ok, suche zu Fuß...");

        for (MyEntity e : set) {
            if (e.equals(entry) && e.hashCode() == entry.hashCode()) {
                System.out.print("Heureka! ");
            }
            System.out.println(e);
        }
    }
}

Was das Programm ausgibt ist folgendes:

Is da!
Ok, suche zu Fuß...
Heureka! Maus
Hund
Katze
---------------
Nixn, kein 'Haus' in tiere!
Ok, suche zu Fuß...
Heureka! Haus
Hund
Katze

Das Objekt MyEntity scheint also aus dem Set zu verschwinden, obwohl es nachweislich da ist. Die Begründung ist leicht: Der HashCode von MyEntity wird nur verwendet, wenn das Objekt in das Set eingetragen wird. Verändere ich das Objekt nachträglich und damit auch den Hashwert, kriegt das Set davon nichts mit. Es wird also innerhalb des Sets unter dem alten Hashwert referenziert.

Es ist also scheinbar keine so wahnsinnig gute Idee Objekte in einem Set zu verändern. Wenn Referenzen auf das Set quer durch alle Klassen verstreut werden, kann man nach so einem Fehler ganz schön lange suchen. 😉

Lang lebe der Rote Zwerg!

Projet Darkstar war eins der coolsten Open Source Projekte da draußen. Ein MMOG-Spielserver mit einer spannenden Architektur und bereits ausgesprochen live tauglich. Oracle hat sich entschlossen, das Sponsoring für diese Projekt einzustellen. Bei einem geradezu explodierendem Markt für alle Arten von Community- und Onlinegames eine Entscheidung, die sich nur mit einem generellen „Big Business“ Focus erklären lässt. 🙂

Wie dem auch sei, das Projekt hat sich umbenannt und ist als Red Dwarf zu neuem Leben erwacht. Wer immer sich mit Online Spielen beschäftigt, sollte sich dieses Projekt genauer anschauen. Es dürfte enorm viel Zeit und Geld sparen. Alle anderen sollten sich das Projekt auch angucken und die Essenz der Architektur in sich aufsaugen, die spannende Lösungen für aktuelle und kommende Web 2.0 Probleme enthält.

Update: Hier der Blog Eintrag zum Start von Red Dwarf.