Как мне получить экземпляр класса универсального типа T?
У меня есть класс generics, Foo<T>. В методе Foo я хочу получить экземпляр класса типа T, но я просто не могу вызвать T.class.
Какой предпочтительный способ обойти это с помощью T.class?
Переведено автоматически
Ответ 1
Короткий ответ заключается в том, что в Java нет способа узнать тип среды выполнения по параметрам универсального типа. Я предлагаю прочитать главу об удалении типов в Руководстве по Java для получения более подробной информации.
Популярным решением этого является передача Class параметра типа в конструктор универсального типа, например
publicvoidbar() { // you can access the typeParameterClass here and do whatever you like } }
Ответ 2
Я искал способ сделать это самостоятельно, не добавляя дополнительную зависимость к classpath. После некоторого исследования я обнаружил, что это возможно, если у вас есть универсальный супертип с неродовым подклассом. Для меня это было нормально, поскольку я работал со слоем DAO с универсальным супертипом layer. Если это соответствует вашему сценарию, то, ИМХО, это самый аккуратный подход.
Большинство универсальных вариантов использования, с которыми я сталкивался, имеют какой-то универсальный супертип, например, List<T> for ArrayList<T> или GenericDAO<T> for DAO<T> и т.д.
@SuppressWarnings("unchecked") public Class reflectClassType() { return ((Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]); }
У этого кода есть несколько ограничений. Он не будет работать во всех случаях, связанных с несколькими уровнями абстракции, или когда ваш тип представляет собой массив (например, int[]). Для более полного решения, которое расширяет это для большего количества случаев, смотрите эту статью .
Еще раз обратите внимание, что этот метод работает только с подклассом, не являющимся универсальным / raw. Если вы попытаетесь сделать это с универсальным классом, аргументы типа останутся неразрешенными, останутся универсальные TypeVariableImpl объекты, классом которых является null. Например:
classGeneric<T>{ @SuppressWarnings("unchecked") public Class reflectClassType() { return ((Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]); } }
// Error! Won't work, since the subclass is generic newChildGeneric<String>().reflectClassType(); // Works; we create an anonymous, trivial, non-generic subclass newChildGeneric<String>(){}.reflectClsasType(); // Works; we create an explicit non-generic subclass newChildString().reflectClassType(); // okay
Spring solution
Spring provides a utility class GenericTypeResolver, which implements a more robust version of this technique. It comes with its own subtle limitations. In general, it will only work if the called for a non-generic class.
My project was using Spring so is the best approach for me as it looks neatest. I guess if you weren't using Spring you could write your own utility method.