2013-09-22 3 views
5

У меня есть POJO, указанный как: MyClass<U>, где U - это типовой параметр типа. Я пытаюсь написать метод утилиты, который принимает ссылку класса Class<T> и заполняет карту типа Map<String, T> (принимает карту для заполнения).Java Generics: как указать тип класса для типичного типизированного класса?

Этот метод реализуется как:

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; 
} 

Это нормально компилируется. В моем абоненте я пытаюсь заполнить карту любым экземпляром MyClass (независимо от типа) в качестве значения. Поэтому я использую следующий код:

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

Это не скомпилировано. Ошибка компиляции:

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

Как это исправить?

+0

Дон» Вы думаете, что при объявлении карты вам нужны фактические типы, а не общие шаблоны? –

+0

Вы должны использовать T везде для этого типа. Можете ли вы вставить полный класс? – Lokesh

+0

@JunedAhsan Нет, я должен был бы создать карту, содержащую все типы экземпляров MyClass. Вот почему я указал шаблон. – Neel

ответ

3

В этом случае она должна быть безопасной, чтобы сделать неконтролируемый бросок к 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); 

Это круговое решение, особенно если у вас много таких сайтов, как это, но не обойти тот факт, что литералы классов параметризуются с помощью сырых типов, что делает их использование в качестве заводов параметризованных типов, таких как MyClass<T>, по своей сути неудобно.

Потенциально чистое решение будет отвязать populateMap от использования класса литералов:

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); 

Как в стороне я рекомендую более гибкую подпись (см What is PECS (Producer Extends Consumer Super)? для получения дополнительной информации):

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

Из-за стирания типа нет объекта типа Class, представляющего общий тип, вы можете использовать только необработанный тип, такой как MyClass (без общего параметра).

Одно из возможных обходных путей является исключительно уродливым: объявите или произведите m как Map<String, MyClass> и подготовьтесь к цунами предупреждений и ошибок (ошибки могут быть устранены путем литья и станут множественными предупреждениями).
Для вероятно, лучше решить эту проблему, обратитесь к ответу Павла :)

Также см Getting a java.lang.Class with generics

+0

"вы можете использовать только необработанный тип, такой как MyClass" Почему не параметр с неограниченным подстановочным параметром, например 'MyClass '? Это, кстати, тип reified. – newacct

+0

@newacct Я не думаю, что вы можете назвать MyClass 'reified type; даже если дженерики были заново обоснованы, это имеет подстановочный знак. Что касается того, почему вы можете получить класс необработанного типа, а не общий тип с подстановочным знаком (который может иметь тот же результат) ... вот как они разработали язык.Но, как показал Пол Беллора, есть трюк, чтобы отдать класс желаемому типу. – aditsu

+0

Я имел в виду «reifiable type» http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.7 "... * Это параметризованный тип, в котором все аргументы типа являются неограниченными подстановочными знаками ". Но да, я думаю, именно так они его разработали. – newacct

Смежные вопросы