Преобразовать java.lang.reflect.Type в класс <T> clazz
Как преобразовать java.lang.reflect.Type
в Class<T> clazz
?
Если у меня есть один метод, следующий, у которого есть аргумент Class<T>
:
public void oneMethod(Class<T> clazz) {
//Impl
}
Затем другой метод, имеющий аргумент java.lang.reflect.Type
и вызывающий oneMethod(Class<T> clazz)
, и для этого мне нужно преобразовать java.lang.reflect.Type type
в Class<T>
:
public void someMehtod(java.lang.reflect.Type type) {
// I want to pass type arg to other method converted in Class<T>
otherMethod(¿How to convert java.lang.reflect.Type to Class<T>?);
}
Возможно ли это?
Ответы
Ответ 1
Вы должны убедиться, что type
является экземпляром Class
, а затем произведите его.
if (type instanceof Class) {
@SuppressWarnings("unchecked")
Class<?> clazz = (Class<?>) type;
otherMethod(clazz);
}
Конечно, вам также придется обрабатывать случай, когда он не является Class
.
Ответ 2
Если вы хотите использовать библиотеку, вы можете использовать com.google.guava:guava:12+
:
Class<?> clazz = com.google.common.reflect.TypeToken.of(type).getRawType();
В качестве альтернативы вы также можете использовать com.fasterxml.jackson.core:jackson-databind:2.8.x
:
Class<?> clazz = com.fasterxml.jackson.databind.type.TypeFactory.rawClass(type);
Это обрабатывает все случаи правильно, и вы получите стертый класс вашего типа.
Ответ 3
Энди Тернер ответит правильно, однако, если вам нужно извлечь класс из параметра типа, это полный пример:
private static class MyClass extends ArrayList<Integer> {
}
public static void main(String[] args) {
ParameterizedType arrayListWithParamType
= (ParameterizedType) MyClass.class.getGenericSuperclass();
Type integerType = arrayListWithParamType.getActualTypeArguments()[0];
Class<?> integerClass = (Class<?>) integerType;
System.out.println(integerClass == Integer.class);
}
Ответ 4
Использование универсальных типов во время выполнения немного сложнее в Java. И я думаю, что это коренная причина вашей проблемы.
1) чтобы быть уверенным в общем во время выполнения, мы делаем так:
class MyClass<E> {}
а потом:
MyClass<TargetType> genericAwaredMyClassInctance = new MyClass<TargetType>(){};
пожалуйста, обратите внимание на {} в конце. Это означает анонимные расширения MyClass. Это важный нюанс.
2) позвольте улучшить MyClass, чтобы иметь возможность извлекать тип во время выполнения.
class MyClass<E> {
@SuppressWarnings("unchecked")
protected Class<E> getGenericClass() throws ClassNotFoundException {
Type mySuperclass = getClass().getGenericSuperclass();
Type tType = ((ParameterizedType)mySuperclass).getActualTypeArguments()[0];
String className = tType.getTypeName();
return (Class<E>) Class.forName(className);
}
}
и, наконец, используйте это так:
MyClass<TargetType> genericAwaredMyClassInctance = new MyClass<TargetType>(){};
assert(genericAwaredMyClassInctance.getGenericClass() == TargetType.class)
Ответ 5
Было бы странно, что Type
будет чем-то другим, чем Class
... Javadoc для Type
говорит
Все известные классы реализации: Класс
Поэтому, если у вас нет специальных библиотек, которые используют не Class
Type
s, вы можете просто выполнить их, но вы должны быть готовы к возможному ClassCastException
.
Опасайтесь: Java использует недокументированную реализацию типа для представления дженериков, см. Ниже.
Вы можете явно обработать его или нет, потому что это исключение:
Явный способ:
try {
Class<?> clazz = (Class<?>) type;
}
catch (ClassCastException ex) {
// process exception
}
Неявный способ:
Class<?> clazz = (Class<?>) type;
но текущий метод может...
EDIT за комментарий @Andy Turner:
Остерегайтесь: Type type = new ArrayList<String>().getClass().getGenericSuperclass();
дает что-то типа, но не класс. Это ParameterizedType
, поэтому вы можете использовать метод getRawType()
для поиска фактического класса, но могут существовать другие.
Ответ 6
Вы имели в виду это?
public <T extends Type> void oneMethod(T clazz) {
}
public void someMethod(Type type) {
oneMethod(type);
}