2012-07-19 4 views
7

Ich versuche, einen Methodenaufruf wie dies zu machen,Wie bekommt Klasse mit Generika-Typen in Java

public class GenericsTest<T> { 

    public static <T> Map<String, T> createMap(Class<? extends Map<String, T>> clazz) { 
     return null; 
    } 

    public static void main(String[] argv) { 
     Map<String, Integer> result = createMap(TreeMap.class); 
    } 
} 

Aber ich diese Störung erhalte,

<T>createMap(java.lang.Class<? extends java.util.Map<java.lang.String,T>>) in test.GenericsTest<T> cannot be applied to (java.lang.Class<java.util.TreeMap>) 

Wie dieses Problem zu beheben?

+0

Sie können das Löschen nicht eingeben. Insbesondere macht die Methodensignatur keinen Sinn, weil Sie versuchen, "T" herauszufordern, obwohl Sie eine "Klasse" für eine "Map" mit dem Wertparameter als "T" einnehmen. Sie können den verschachtelten Typ nie ohne eine vorhandene Instanz des Objekts abrufen. (Sie könnten '(new HashMap ()). GetClass()' übergeben, aber Sie können "Integer" immer noch nicht aus dieser Methode herausholen. – pickypg

+0

Die createMap() stammt aus einer Bibliothek, die wir verwenden. Es muss einen Weg geben, diese Methode aufzurufen. –

+0

Ich frage die Legitimität des zurückgegebenen Objekts. Es gibt angeblich eine Instanz des Wertparameters "T" zurück, wenn es in der "Klasse" für eine "Map" übergeben wird, und der Methodenname lautet "createMap". Nichts davon ergibt irgendeinen Sinn. – pickypg

Antwort

3
Map<String, Integer> instance = new TreeMap<String, Integer>(); 

@SuppressWarnings("unchecked") 
Map<String, Integer> map = 
    createMap((Class<? extends Map<String, Integer>>)instance.getClass()); 

map.put("x", 1); 

System.out.println("THIS IS x: " + map.get("x")); 

Dies wird aus 1. Die Durchführung des Verfahrens in geeigneter Weise gedruckt ist höchstwahrscheinlich

try 
{ 
    return clazz.newInstance(); 
} 
catch (Exception e) 
{ 
    throw new RuntimeException(e); 
} 

Eine bessere Umsetzung ihrer API für sie sein würde Sie für die fragen, T, und für sie geben eine Map ihrer Wahl zurück, anstatt Sie für alle Details zu fragen. Ansonsten, solange sie nicht mit Daten im Map füllen, können Sie eine Map mit dem generischen Typ Argument instanziiert sich wie folgt:

public static <T> Map<String, T> getMap() 
{ 
    return new TreeMap<String, T>(); 
} 

Sie können dann, dass zugreifen, ohne eine Warnung:

// note the lack of type arguments, which are inferred 
Map<String, Integer> instance = getMap(); 

// alternatively, you could do it more explicitly: 
// Map<String, Integer> instance = ClassName.<Integer>getMap(); 

Es gibt wirklich keinen Grund für sie Sie für die Class Typ Ihres Map außer Sie zu bitten, eine genaue Übereinstimmung mit der Umsetzung zurück zu geben (zB wenn Sie in einem HashMap halten, dann werden Sie eine HashMap zurück, und wenn Sie stecken in eine , dann erhalten Sie wieder eine). Ich vermute jedoch, dass die TreeMap alle Comparator verlieren wird, mit denen es konstruiert wurde, und da das ein unveränderliches (final) Feld von TreeMap ist, dann können Sie das nicht beheben; das bedeutet, dass die Map in diesem Fall nicht das gleiche ist, noch ist es wahrscheinlich, was Sie wollen.

Wenn sie die Map mit Daten ausfüllen, dann macht es noch weniger Sinn. Sie könnten immer eine Instanz von Map zum Füllen übergeben, oder haben Sie eine Map zurückgeben, die Sie einfach umbrechen können (z. B. new TreeMap<String, Integer>(instance);), und sie sollten wissen, welche Map bietet die meisten Nutzen für die Daten.

+0

Dies läuft aber mit der ungeprüften Warnung. Es muss eine Möglichkeit geben, diese Methode ohne Warnung aufzurufen. Das ist der ganze Zweck der Verwendung von Generika. –

+0

Sie haben Recht mit dem Zweck, aber Java hat Generika wegen Type Erasure begrenzt, die dieses Problem verursacht; Es gibt Einschränkungen, was Sie tun können, ohne den Compiler dazu bringen zu müssen, es für Sie zu tun. Es ist wahrscheinlich meine unbeliebteste Eigenschaft von Java, weil es für sie am schwierigsten ist, sie zu reparieren oder zu ersetzen. .NET hat ein vielseitigeres Generikasystem, weil es zur Laufzeit nicht vergessen wird. Nach der Kompilierung wird dieser Map-Zugriff zu '(Integer) map.get (" x ")', weil der zurückgegebene Typ tatsächlich 'Object' ist. – pickypg