2013-09-22 15 views
5

Mam POJO określone jako: MyClass<U>, gdzie U jest parametrem typu ogólnego. Próbuję napisać metodę narzędzia, która akceptuje odwołanie do klasy Class<T> i zapełnia mapę typu Map<String, T> (akceptuje mapę do wypełnienia).Java Generics: Jak określić typ klasy dla ogólnej klasy pisanej?

Metoda ta jest realizowana jak:

static void populateMap(Map<String, T> map, Class<T> type) { 

    ... 

    // Parses into the specified type and returns an object of that type. 
    T obj = parse(..., type); 
    map.put (key, obj); 
    ... 

    return map; 
} 

To kompiluje grzywny. W moim programie wywołującym, próbuję wypełnić mapę dowolną instancją MyClass (niezależnie od typu) jako wartością. Dlatego używam następującego kodu:

// Loses type information 
Map<String, MyClass<?>> m = new HashMap<>(); 
populateMap(m, MyClass.class); 

To nie kompiluje. Błąd kompilacji:

The method populate(Map<String,T>, Class<T>) in the type ... is not applicable for the arguments (Map<String,MyClass<?>>, Class<MyClass>)

Jak mogę to naprawić?

+0

Don” Czy myślisz, że podczas deklarowania mapy potrzebujesz prawdziwych typów, a nie generycznych symboli wieloznacznych? –

+0

Powinieneś używać T wszędzie dla tego typu. Czy możesz wkleić pełną klasę? – Lokesh

+0

@JunedAhsan Nie, powinienem móc utworzyć mapę zawierającą dowolny typ instancji MyClass. Właśnie dlatego podałem symbol wieloznaczny. – Neel

Odpowiedz

3

W tym przypadku powinno być bezpieczne niesprawdzany obsady do Class<MyClass<?>>:

// This is okay because we're switching to a type with an unbounded wildcard - 
// the behaviors of Class.newInstance and Class.cast are still safe. 
@SuppressWarnings("unchecked") 
Class<MyClass<?>> classWithNarrowedType = 
     (Class<MyClass<?>>)(Class<?>)MyClass.class; 
populateMap(m, classWithNarrowedType); 

Jest to rozwiązanie typu crufty, zwłaszcza jeśli masz wiele takich witryn wywoływania, ale nie ma problemu z tym, że literały klas są sparametryzowane za pomocą typów surowych, dzięki czemu ich użycie jako fabryk parametrów sparametryzowanych, takich jak MyClass<T>, jest z natury niezręczne.

Potencjalnie czystsze rozwiązaniem byłoby oddzielenie populateMap z użycia literałów Klasa:

interface Parser<T> { 

    T parse(); 
} 

static void populateMap(Map<String, T> map, Parser<T> parser) { ... } 

... 

Map<String, MyClass<?>> m = new HashMap<>(); 
Parser<MyClass<?>> myClassParser = new Parser<MyClass<?>>() { 
    @Override 
    public MyClass<?> parse() { 
     return parse(..., MyClass.class); 
    } 
}; 
populateMap(m, myClassParser); 

Tak na marginesie polecam bardziej elastyczne podpisu (patrz What is PECS (Producer Extends Consumer Super)? aby uzyskać więcej informacji):

static void populateMap(Map<String, ? super T> map, Parser<T> parser) 
2

Z powodu usunięcia typu nie ma czegoś takiego jak obiekt klasy reprezentujący rodzaj ogólny, można użyć tylko typu surowego, takiego jak MyClass (bez parametru rodzajowego).

Jedno możliwe obejście jest wyjątkowo brzydkie: zadeklaruj lub odrzuć m jako Map<String, MyClass> i przygotuj się na stawienie czoła tsunami z ostrzeżeniami i błędami (błędy można naprawić, rzucając i stają się wielokrotnymi ostrzeżeniami).
przypadku chyba lepiej obejść, patrz Pawła odpowiedź :)

zobaczyć również Getting a java.lang.Class with generics

+0

"można używać tylko typu surowego, takiego jak MyClass" Dlaczego nie ma parametru typu bez ograniczeń, np. 'MyClass '? Która jest zresztą typem reifikowanym. – newacct

+0

@newacct Nie sądzę, że można nazwać 'MyClass ' reified type; nawet jeśli generics zostały reifikowane, to ma symbol wieloznaczny. Co do tego, dlaczego można uzyskać tylko klasę typu surowego, a nie rodzajowego z symbolem wieloznacznym (który może mieć taki sam wynik) ... tak zaprojektowali język.Ale jak pokazał Paul Bellora, istnieje pewna sztuczka, aby rzucić klasę na pożądany typ. – aditsu

+0

Miałem na myśli typ "rewiowy" http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.7 "... * Jest to typ sparametryzowany, w którym wszystkie Argumenty typu to nieokreślone symbole wieloznaczne ". Ale tak, myślę, że tak właśnie to zaprojektowali. – newacct

Powiązane problemy