Generics - Map.putAll lässt sich nicht richtig implementiern

  • Themenstarter Themenstarter Geralth
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Geralth

Gast
Hallo,

ich versuche gerade die Methode java.util.Map.putAll zu implementieren, meines Wissens nach sollte folgender Code eigentlich funktionieren (abgesehen vom fehlenden Rückgabewert), allerdings bemängelt der Compiler immer, dass der Rückgabetyp von entrySet nicht zu meiner Deklaration des Sets passt.

Hier der Code:
Java:
public void putAll( Map< ? extends K, ? extends V > entries ) {
        Set< Map.Entry< ?, ? > > set = entries.entrySet();
    }

Der Compiler meldet:
found : java.util.Set<java.util.Map.Entry<capture#695 of ? extends K,capture#713 of ? extends V>>
required: java.util.Set<java.util.Map.Entry<?,?>>
Set< Map.Entry< ?, ? > > set = entries.entrySet();

Habt ihr eine Idee was daran falsch ist?
 
http://mail-archives.apache.org/mod...0404s22291a5cma61e16824805791@mail.gmail.com>

> > It's a tricky one to be sure.
> >
> > The problem is that the entrySet() method is returning a
> > "Set<Map.Entry<capture-of ? extends K, capture-of ? extends V>>",
> > which is incompatible with the type "Set<Map.Entry<? extends K, ?
> > extends V>>". It's easier to describe why if I drop the "extends K"
> > and "extends V" part. So we have "Set<Map.Entry<?, ?>" and
> > "Set<Map.Entry<capture-of ?, capture-of ?>>".
> >
> > The first one, "Set<Map.Entry<?, ?>>" is a set of Map.Entries of
> > different types - ie it is a heterogeneous collection. It could
> > contain a Map.Entry<Long, Date> and a Map.Entry<String, ResultSet>>
> > and any other pair of types, all in the same set.
> >
> > On the other hand, "Set<Map.Entry<capture-of ?, capture-of ?>>" is a
> > homogenous collection of the same (albeit unknown) pair of types. Eg
> > it might be a Set<Map.Entry<Long, Date>>, so all of the entries in the
> > set MUST be Map.Entry<Long, Date>.
> >
> > In general, even if you could assign this to a local variable without
> > unchecked type safety warnings, you wouldn't be able to call any
> > methods on it because the compiler cannot check whether the access is
> > type-safe. For example you would not be able to call add() because the
> > Set must contain a specific type, but the compiler doesn't know which
> > specific type that is!
 
Danke, dann ist klar warum es nicht geht und ich habe jetzt einfach so eine Schleife wie in dem Beitrag benutzt, da ich eh einmal drüberiterieren möchte.
 
Das Problem mit "generics" in irgendwelchen Maps scheint ja nach wie vor recht populär zu sein...

Nun habe ich eben genau dieses Problem auch gehabt. Hier ist mein Lösungsvorschlag:
Code:
private void putAll0(Map<String, String> m)
{
    Map.Entry<String, String> e;
    Iterator<Map.Entry<String, String>> i = m.entrySet().iterator();
    while(i.hasNext()) {
        e = i.next();
        if(e.getKey() != null && !e.getKey().equals("")) {
            if(containsKey(e.getKey())) getEntry(e.getKey()).setValue(e.getValue());
            else intern.add(e);
        }
    }
}

@SuppressWarnings("unchecked")
@Override
public void putAll(Map<? extends String, ? extends String> m)
{
    try {
        putAll0((Map<String, String>) m);
    } catch(Exception e) {
        // ignore
    }
}

private Map.Entry<String, String> getEntry(String key)
{
    Map.Entry<String, String> e;
    Iterator<Map.Entry<String, String>> i = intern.iterator();
    while(i.hasNext()) {
        e = i.next();
        if(e.getKey().equals(key)) return e;
    }
    return null;
}
Die Verwendung der Klasse String ist projektbezogen und kann in individuellen Implementierungen verändert werden.
Soll noch angemerkt werden, das "intern" eine ArrayList<Map.Entry<String, String>" ist und die Map vom Typ "Map<String, String>" leere Strings bzw. null als Schlüssel nicht zulässt. Als letztes frage ich mich, ob "? extends String" überhaupt Sinn macht... warum wohl... 🙂

mfg Spacerat
 
wenn die Klassen feststehen, wieso dann überhaupt eine generische Methode?
für den allgemeinen Fall dürfte das doch nicht helfen
 
SlaterB hat gesagt.:
wenn die Klassen feststehen, wieso dann überhaupt eine generische Methode?
für den allgemeinen Fall dürfte das doch nicht helfen
Ich bin ganz deiner Meinung, aber sag das mal dem Compiler (Eclipse). Normalerweise würde "putAll(Map<String, String> m)" völlig ausreichen. Das ergibt in Eclipse aber die Fehlermeldung "putAll(Map<String, String>) doesn't override putAll(Map<? captureOf String, ? captureOf String>)". Und das, wie schon angedeutet sogar bei "final" Klassen (im Beispiel: String). Und btw... für den allgemeinen Fall muss "String" nur durch die jeweils benötigten Klassen ersetzt werden, also auch durch K und V.

cu Spacerat
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Zurück
Oben