Eigene equals+hashCode-Funktionen für Sets und Maps

Doch, die passen zusammen. Die containsKey ist klar definiert: ~“Enhält einen key, der equals zum übergebenen ist”. Und die KeySet liefert die Menge aller Keys - welche auch immer das sind, auf jeden Fall sind sie equals zu denen, die für “put” verwendet wurden.

Aber wenn man wirklich diese “WrapFunction” als Konfigurationspunkt nach draußen anbieten würde, wäre ja nicht mal der TYP richtig: Eine Map<String,X> würde dann als KeySet ggf. eine Set liefern. (Und eine “UnwrapFunction” wäre weder sinnvoll noch praktisch möglich…)

im Moment sieht es mit Code von Posting 1, falls noch nicht zwischenzeitlich korrigiert, dazu übrigens so aus:

        System.out.println(map0.containsKey("AAa")); // true
        System.out.println(map0.keySet().contains("AAA")); // true
        System.out.println(map0.keySet().contains("AAa")); // false

das erste true fürs keySet auch nur mit der Default-Implementierung von AbstractCollection, welche den Iterator durchläuft bis gefunden,

mit einfacher Ergänzung

                public boolean contains(Object o)
                {
                    return containsKey(o);
                }

wie auch in der HashMap-API-Klasse läuft es dahingehend sicher performanter und dann auch alle 4 true


ein HashSet verwendet intern eine HashMap, der Code in der API ist wirklich aufgeräumt,
bis auf clone und Serialisierung keine Methode oder Konstruktor über 2 Zeilen, alles geht auf die Map

wäre für dich vielleicht auch eine Variante, WrapperSet mit intern WrapperMap, schon bedacht?

OK, konzeptuell passen sie zusammen - auch wenn die aktuelle Implementierung offenbar Murx/Buggy ist :o

Der Zusammenhang zwischen Set und Map ist in etwa(!) klar, aber bei genauerer Betrachtung (bzw. Implementierung) dann doch etwas verwirrend: HashSet verwendet eine HashMap, ja, aber um das “Map”-Interface zu implementieren, muss man eigentlich NUR eine “entrySet()” zurückgeben können. Das ist aber natürlich KG in bezug auf die Performance, weil dann alles über die Iterationen aus AbstractCollection gelöst wird - deswegen sind ja die ganzen Methoden aus “AbstractMap” (wie im Kommentar erwähnt) nochmal überschrieben.
Ob es in DIESEM Fall möglich ist, die Set auf die Map abzubilden hängt stark davon ab, an welchen Stellen dann wie das “wrap” passiert. Aber es kann gut sein, dass das ohne Probleme geht - da muss ich mal genauer schauen.

Soll dein keySet jetzt intern die Wrapper mitschleppen - (also selbst die neuen, übergebenen equals/hashcode verwenden) oder soll das ein Set der Original-Objekte sein (muss es laut API ja)?

Das KeySet MUSS die Wrapper mitschleppen (was ein etwas (um das Wort auch mal zu verwenden) “bösartiger” Begriff ist: Das ist ja kein zusätzlicher Overhead zu dem, was sowieso schon in der Map ist). Aber nur intern. Nach außen hin muss sie natürlich “aussehen” wie eine Set (und nicht wie eine Set), das ist ja klar. Aber das sollte alles mit relativ wenig Aufwand machbar sein, durch die “Abstract*”-Basisimplementierungen und ggf. einen Iterator hier oder da, der die Originalobjekte der gewrappten Objekte zurückgibt.

1.Fall: keySet verwendet auch die neuen equals/hashCode

Der Aufrufer von keySet muss ** irgendwoher wissen**, dass es NICHT wie ein Set funktioniert (weil equals/hashCode anders funktionieren als erwartet).

Sagen wir mal, du machst ein Map<Integer,FooBar> und überschreibst equals/hashCode so, dass effektiv modulo 37 gerechnet wird. Dann holt sich einer (ein Programmierer auf den Malediven) das keySet ab und hat ein Set in der Hand. Das aber keines ist.

2.Fall keySet verwendet NICHT die neuen equals/hashCode

dann sind mymap.containsKey und keySet.contains definitiv nicht kompatibel

[QUOTE=Bleiglanz]1.Fall: keySet verwendet auch die neuen equals/hashCode

Der Aufrufer von keySet muss ** irgendwoher wissen**, dass es NICHT wie ein Set funktioniert (weil equals/hashCode anders funktionieren als erwartet).

Sagen wir mal, du machst ein Map<Integer,FooBar> und überschreibst equals/hashCode so, dass effektiv modulo 37 gerechnet wird. Dann holt sich einer (ein Programmierer auf den Malediven) das keySet ab und hat ein Set in der Hand. Das aber keines ist.
[/QUOTE]

Das stimmt, und das hatte ich so konkret nicht bedacht. So gesehen entspricht die ganze Map aber schon nicht mehr dem Map-Interface, weil dort ja immer nur von DEM „equals“ der Key-Objekte die Rede ist. Es ist jetzt nicht so, dass das beispiellos wäre …

… aber man sollte klar machen, dass es keine „normale“ Map (in diesem Sinne) ist, woraus sich auch ergibt, dass das KeySet kein „normales“ Set ist.

Hab’ da jetzt nochmal kurz geschaut: Es krankt halt an den im Code noch stehen gelassenen Funktionen: „wrap“ dürfte keine ClassCastException werfen, weil sie ja in „contains“ aufgerufen wird (und die keine ClassCastException werfen darf).