Дженерики Java: получить класс возвращаемого типа универсального метода

Фон

Однажды я написал такой метод:

private <T> SortedSet<T> createSortedSet() {
  return new TreeSet<T>();
}

Он должен называться так:

Set<String> set = createSortedSet();

Это отлично работает (хотя я видел здесь ответы при исследовании текущего вопроса, что это подвержено ошибкам).

Текущая ситуация

В любом случае, сейчас я пишу следующий код (в классе, расширяющем javax.servlet.jsp.tagext.TagSupport):

private <T> T evaluate(String expression) {
  ExpressionEvaluator evaluator = pageContext.getExpressionEvaluator();
  return evaluator.evaluate(expression, T, null, pageContext.getVariableResolver());
}

Цель состоит в том, чтобы иметь возможность называть это так:

Integer width = evaluate(widthStr);

Код в моем методе оценки явно не работает. Второй аргумент evaluator.evaluate() должен быть объектом класса. Это приводит меня к следующему:

Мой вопрос

Как я могу получить класс универсального (возвращаемого) типа? Что я должен написать вместо T в качестве второго аргумента для оценки?

РЕДАКТИРОВАТЬ: Заключение

Николас, кажется, прав, это невозможно, и мне нужно передать класс в качестве аргумента моему методу. Положительным моментом является то, что, поскольку его решение делает аргумент параметризованным для универсального типа, я получаю проверку компиляции для этого аргумента.


person Peter Jaric    schedule 18.11.2010    source источник


Ответы (2)


К сожалению, вам непременно придется изменить свой метод на:

private <T> T evaluate(Class<T> clazz, String expression)

а затем передайте clazz в качестве второго параметра. Не так коротко, как вы ожидали.

person Nicolas    schedule 18.11.2010
comment
Спасибо! После экспериментов с различными идеями, основанными на отражении, я не могу не согласиться с вами. - person Peter Jaric; 18.11.2010
comment
В основном проблема возникает из-за docs.oracle.com/javase/tutorial/ java / generics / erasure.html - person maxammann; 17.04.2014

# ff0000Это работает не со всеми JVM!

Вы можете сначала создать универсальный объект, а затем получить его параметризованный тип:

private <T> T evaluate(String expression) {
  List<T> dummy = new ArrayList<>(0);
  Type[] actualTypeArguments = ((ParameterizedType) dummy.getClass().getGenericSuperclass()).getActualTypeArguments();
  Type clazz = actualTypeArguments[0];
  Class<T> theClass = (Class<T>) clazz.getClass();

  ExpressionEvaluator evaluator = pageContext.getExpressionEvaluator();
  return evaluator.evaluate(expression, theClass, null, pageContext.getVariableResolver());
}

Остерегаться! Вы не получаете объект Class<>, вы получаете объект подкласса TypeVariableImpl, который может вести себя по-другому.

person Fabrice TIERCELIN    schedule 30.04.2019