我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
当前回答
标准方法/解决方法/解决方案是向构造函数中添加类对象,例如:
public class Foo<T> {
private Class<T> type;
public Foo(Class<T> type) {
this.type = type;
}
public Class<T> getType() {
return type;
}
public T newInstance() {
return type.newInstance();
}
}
其他回答
我根据这个问题中两个最有希望的解决方案之一创建了一个示例。
然而,至少在我的用例中,结果并不那么有希望。
只有一种方法有效,但您需要一个包含方法的超级类,泛型必须在子类中设置,并且不能动态分配(我的用例很遗憾)
import org.junit.jupiter.api.Test;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class GenericTest {
/**
* only this will work!
*/
@Test
void testGetGenericTypeClassFromChildClassWithSpecifiedType() {
TestClassWithSpecifiedType parent = new TestClassWithSpecifiedType();
assertEquals(SomeGenericType.class, parent.getGenericTypeClass());
}
/**
* won't work!
*/
@Test
void testGetGenericTypeClassFromChildClassWithUnspecifiedType() {
TestClassWithUnspecifiedType<SomeGenericType> parent = new TestClassWithUnspecifiedType<>();
assertThrows(IllegalStateException.class, parent::getGenericTypeClass);
}
/**
* won't work
*/
@Test
void testGetGenericTypeClassWithUnspecifiedType() {
SomeGenericTypedClass<SomeGenericType> parent = new SomeGenericTypedClass<>();
assertThrows(IllegalStateException.class, parent::getGenericTypeClass);
}
/**
* won't work
* returns object instead!
*/
@Test
void testGetLoadedClassFromObject() {
Foo<SomeGenericType> foo = new Foo<>();
Class<?> barClass = foo.getBarClass();
assertEquals(SomeGenericType.class, barClass);
}
/**
* A class that has specified the type parameter
*/
public static class TestClassWithSpecifiedType extends AbstractGenericTypedClass<SomeGenericType> {
}
/**
* A class where the type parameter will be specified on demand
*
* @param <T>
*/
public static class TestClassWithUnspecifiedType<T> extends AbstractGenericTypedClass<T> {
}
/**
* An abstract class, because otherwise finding the parameter will not work
*/
@SuppressWarnings("unchecked")
public static abstract class AbstractGenericTypedClass<T> {
@SuppressWarnings("unchecked")
public Class<T> getGenericTypeClass() {
try {
String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
return (Class<T>) clazz;
} catch (Exception e) {
throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
}
}
}
/**
* A typed class without abstract super class
*
* @param <T>
*/
public static class SomeGenericTypedClass<T> {
@SuppressWarnings("unchecked")
public Class<T> getGenericTypeClass() {
try {
String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
return (Class<T>) clazz;
} catch (Exception e) {
throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
}
}
}
/**
* Some generic type - won't work with primitives such as String, Integer, Double!
*/
public static class SomeGenericType {
}
public static class Foo<T> {
// The class:
private final Class<?> barClass;
public Foo() {
try {
// Im giving it [0] cuz Bar is the first TypeParam
Type[] bounds = getClass().getTypeParameters()[0].getBounds();
// Here, we get the class now:
barClass = Class.forName(bounds[0].getTypeName());
} catch (ClassNotFoundException e) {
// will never happen!
throw new Error("Something impossible happened!", e);
}
}
public Class<?> getBarClass() {
return barClass;
}
}
}
我真的不明白为什么这必须如此复杂,但我敢打赌,动态设置参数必须有一些技术限制。
这个问题由来已久,但现在最好的办法是使用谷歌Gson。
获取自定义视图模型的示例。
Class<CustomViewModel<String>> clazz = new GenericClass<CustomViewModel<String>>().getRawType();
CustomViewModel<String> viewModel = viewModelProvider.get(clazz);
泛型类型类
class GenericClass<T>(private val rawType: Class<*>) {
constructor():this(`$Gson$Types`.getRawType(object : TypeToken<T>() {}.getType()))
fun getRawType(): Class<T> {
return rawType as Class<T>
}
}
比其他人建议的类更好的方法是传入一个对象,该对象可以执行您对类所做的操作,例如创建一个新实例。
interface Factory<T> {
T apply();
}
<T> void List<T> make10(Factory<T> factory) {
List<T> result = new ArrayList<T>();
for (int a = 0; a < 10; a++)
result.add(factory.apply());
return result;
}
class FooFactory<T> implements Factory<Foo<T>> {
public Foo<T> apply() {
return new Foo<T>();
}
}
List<Foo<Integer>> foos = make10(new FooFactory<Integer>());
这是一个有效的解决方案:
@SuppressWarnings("unchecked")
private Class<T> getGenericTypeClass() {
try {
String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
Class<?> clazz = Class.forName(className);
return (Class<T>) clazz;
} catch (Exception e) {
throw new IllegalStateException("Class is not parametrized with generic type!!! Please use extends <> ");
}
}
笔记:只能用作超类
必须使用类型化类进行扩展(Child扩展Generic<Integer>)
OR
必须创建为匿名实现(new Generic<Integer>(){};)
我找到了一种通用而简单的方法。在我的类中,我创建了一个方法,该方法根据泛型类型在类定义中的位置返回泛型类型。让我们假设一个类定义如下:
public class MyClass<A, B, C> {
}
现在,让我们创建一些属性来持久化类型:
public class MyClass<A, B, C> {
private Class<A> aType;
private Class<B> bType;
private Class<C> cType;
// Getters and setters (not necessary if you are going to use them internally)
}
然后,您可以创建一个基于泛型定义的索引返回类型的泛型方法:
/**
* Returns a {@link Type} object to identify generic types
* @return type
*/
private Type getGenericClassType(int index) {
// To make it use generics without supplying the class type
Type type = getClass().getGenericSuperclass();
while (!(type instanceof ParameterizedType)) {
if (type instanceof ParameterizedType) {
type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
} else {
type = ((Class<?>) type).getGenericSuperclass();
}
}
return ((ParameterizedType) type).getActualTypeArguments()[index];
}
最后,在构造函数中,只需调用方法并发送每个类型的索引。完整的代码应该如下所示:
public class MyClass<A, B, C> {
private Class<A> aType;
private Class<B> bType;
private Class<C> cType;
public MyClass() {
this.aType = (Class<A>) getGenericClassType(0);
this.bType = (Class<B>) getGenericClassType(1);
this.cType = (Class<C>) getGenericClassType(2);
}
/**
* Returns a {@link Type} object to identify generic types
* @return type
*/
private Type getGenericClassType(int index) {
Type type = getClass().getGenericSuperclass();
while (!(type instanceof ParameterizedType)) {
if (type instanceof ParameterizedType) {
type = ((Class<?>) ((ParameterizedType) type).getRawType()).getGenericSuperclass();
} else {
type = ((Class<?>) type).getGenericSuperclass();
}
}
return ((ParameterizedType) type).getActualTypeArguments()[index];
}
}