2013-10-08 10 views
6

Ich habe eine Frage zu Java-Generika. Sagen, ich habe die folgende Schnittstelle:Java - Generika & Wildcards & Schnittstelle versus Implementierung

public static class Something<T> { 
    public void set(T t) { 
    } 
} 

public static interface Manager<T> { 
    public void add(final String key, final Something<T> o); 

    public Something<T> get(final String key); 
} 

Ein Beispiel für die Nutzung:

final Manager<Number> m = ...; 

m.add("key", new Something<Number>()); 
m.get("key").set(new Integer(5)); 

Ich würde auch Something<Integer>, in der Lage sein möge hinzufügen Something<Double>, ... zum einem Manager<Number>. Ich würde sagen, ich habe die Unterschrift der Add-Funktion zu ändern:

public static interface Manager<T> { 
    public void add(final String key, final Something<? extends T> o); 

    public Something<T> get(final String key); 
} 

final Manager<Number> m = ...; 

m.add("key", new Something<Integer>()); 
m.get("key").set(new Integer(5)); 

So weit, so gut. Lassen Sie sich bei einer möglichen Implementierung des Managers aussehen:

public static class ManagerImplementation<T> implements Manager<T> { 
    protected HashMap<String, Something<T>> map = new HashMap<String, Something<T>>(); 

    public void add(final String key, final Something<? extends T> o) { 
     map.put(key, o); // <--- here 
    } 

    public Something<T> get(final String key) { 
     return map.get(key); 
    } 
} 

Dies schlägt fehl, da Sie keine Something<? extends T> zu einem Map<X, Something<T>> hinzufügen können. Also lassen Sie uns dies ändern:

public static class ManagerImplementation<T> implements Manager<T> { 
    protected HashMap<String, Something<? extends T>> map = new HashMap<String, Something<? extends T>>(); 

    public void add(final String key, final Something<? extends T> o) { 
     map.put(key, o); 
    } 

    public Something<T> get(final String key) { 
     return map.get(key); // <--- here 
    } 
} 

Dies schlägt fehl, da map.get(key) kehrt Something<? extends T> während die get-Funktion erforderlich ist Something<T> zurückzukehren, wie es in der Schnittstelle definiert.

Was ist der übliche Ansatz, um dies zu lösen?

Danke!

+0

Warum können Sie die get-Methode in der Schnittstelle zum 'öffentlichen Etwas get (final String key) nicht ändern,' auch? –

+1

@HariShankar dies wird 'Something ' zurückgeben, so dass OP nicht in der Lage sein wird, irgendwas über eine solche Referenz zu 'setzen' (außer' null'). – Pshemo

Antwort

3

Innerhalb Ihrer Klasse verwenden Sie immer Something<? extends T>, also müssen Sie in Ihrer public get Methode die Innenwelt in das Außenweltformat konvertieren. Z.B. Sie können einfach das Ergebnis von map.get(key)-Something<T> Stimmen:

return (Something<T>) map.get(key); // <--- here 
+0

Ich bin ziemlich neu für Generika. Ich hatte immer die Idee, dass Sie Abgüsse vermeiden können, wenn Generika vorhanden sind. Das ist also nicht wahr? Das kann nur korrekt gelöst werden, wenn man einen Cast benutzt? – user1284566

+0

Aus praktischer Sicht ist mein Ratschlag: Verwenden Sie Generika, aber verwenden Sie sie nur spärlich. Normalerweise genügt ein Generika-Grad (wie '', no extends oder super), alles andere ist zu kompliziert und macht den Code unlesbar. Mit einem Schwerpunkt auf "normalerweise". ;-) – LastFreeNickname

+0

Mit anderen Worten, du sagst, dass die Generika für die Außenwelt/API wie erwartet sein müssen (wenn nötig mit Platzhaltern), aber für die Implementierung ist es am besten, sie so einfach wie möglich zu halten? – user1284566

Verwandte Themen