2011-02-12 5 views
15

Моя цель - разработать класс, который может выводить объект определенного класса.Как передать параметризованный класс в качестве аргумента

public class GetMe<T> { 
    public T get() { 
     Object obj = generateObject(); 
     return (T) obj; 
    } 
} 

Теперь я знаю, что это невозможно из-за стирания. Итак, мы можем передать экземпляр класса и использовать его для создания.

public class GetMe<T> { 
    public GetMe<T>(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    public T get() { 
     Object obj = generateObject(); 
     return clazz.cast(obj); 
    } 
} 

Это отлично работает! Пока класс не параметризуется. Если да, то у меня проблема.

Мне не разрешено использовать List<String>.class. Если я передаю параметр ParameterizedType (который сам по себе трудно сгенерировать), то нет метода cast.

Есть ли выход из этой трясины?

+0

Существует способ сохранить generics во время выполнения, но что такое 'generateObject' и почему он не может вернуть объект типа' T'? – ide

+0

посмотрите на эти примеры, может помочь: http://serdom.eu/ser/2007/03/25/java-generics-instantiating-objects-of-type-parameter-without-using-class-literal –

+0

Предположим, generateObject() '- сторонний десериализатор. Я знаю, что это тип T, потому что я сериализую его раньше, но метод тем не менее возвращает Object. Это также может быть результатом метода.invoke, который возвращает объект только. –

ответ

2

Проблема с List<String> заключается в том, что из-за стирания это было бы во время выполнения неотличимым от любых других List<?>. Самый простой способ обойти это, чтобы создать новый класс или интерфейс, который имеет общую часть «фиксированную», как

public interface StringList extends List<String> { 
    /* nothing to see here */ 
} 

Таким образом у вас есть тип маркера (StringList.class объекта), который вы можете пройти вокруг во время выполнения и точно определяет то, что вы хотите, но без необходимости создания дженериков во время выполнения.

+0

Мне нравится эта идея, но разве мне не нужно было бы многие из этих «фиксированных» классов? »Есть ли способ заставить их работать Я использовал список в моем примере, в моем проекте это фактически «Карта >», где Domain может быть одним из объектов ~ 200, некоторые из которых сами параметризуются. –

1

Вот только небольшая идея. Я не уверен, что это будет соответствовать вашему контексту, но тем не менее:

public class GetMe<T> 
{ 
    public List<T> getList() { 
     @SuppressWarnings("unchecked") 
     List<T> result = (List<T>) new LinkedList(); 
     return result; 
    } 
} 

Cheers!

+1

где я склоняюсь, так что я могу продолжать свою жизнь (хотя это «менее корректно»). –

5

Я думаю, super type tokens может решить эту проблему для вас.

+0

+1 потому что маркеры супер-типа являются сверхгибкими. Должен упомянуть их в моем ответе. – Waldheinz

0

Первая проблема заключается в том, как вы планируете создать объект List. Если вы раскрываете больше того, что пытаетесь построить, мы можем помочь вам лучше.

Возможно, вы захотите использовать Type вместо класса. Тип может представлять все общие типы, хотя работать с ними не приятно.

abstract public class GetMe<T> 
{ 
    Type type; 
    public GetMe<T>(Type type) 
    { 
     this.type = type; 
    } 
} 

Другая проблема заключается в том, чтобы создать общий тип, как List<String>. «Маркер супер типа» выглядит аккуратным в синтаксисе, на самом деле это в основном

static class XX extends TypeReference<List<String>>{} 
.... 
Type typeListString = Util.extract(XX.class); 

Я предпочел бы этого путь

List<String> f; 

Type typeListString = getDeclaredField("f").getGenericType(); 

На самом деле, многие из этих рамок, которые делают фантазию выполнения общей Магия работает на только поля экземпляра.

0

Я думаю, что путаница происходит из-за того, что вы пытаетесь создать объект с List<>, который на грани этого интерфейса, а не объекта.
Поэтому независимо от того, что вы попробуете, вы просто не можете создать экземпляр List<> (интерфейсы не являются фактическими классами, и не имеете конструкторов)

Попробуйте использовать ограничение, чтобы избежать интерфейсов ставить в объявлении:

public class GetMe<T extends Object> 

Это будет гарантировать, что T является фактический класс, а не интерфейс.

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