我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
当前回答
这个问题由来已久,但现在最好的办法是使用谷歌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>
}
}
其他回答
正如其他答案中所解释的,要使用这种ParameterizedType方法,您需要扩展该类,但创建一个扩展它的新类似乎需要额外的工作。。。
因此,使类抽象化会迫使您扩展它,从而满足子类化要求。(使用lombok的@Getter)。
@Getter
public abstract class ConfigurationDefinition<T> {
private Class<T> type;
...
public ConfigurationDefinition(...) {
this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
...
}
}
现在在不定义新类的情况下扩展它。(请注意末尾的{}…扩展,但不要覆盖任何内容,除非您愿意)。
private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){};
private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){};
...
Class stringType = myConfigA.getType();
Class fileType = myConfigB.getType();
实际上,我想你的类中有一个T型字段。如果没有T型字段,那么有一个泛型类型有什么意义?因此,您可以简单地在该字段上执行实例化。
在我的情况下,我有一个列表<T>项;在我的类中,我检查类类型是否为“Locality”
if (items.get(0) instanceof Locality) ...
当然,这只在可能的类总数有限的情况下有效。
简单的答案是,无法找出Java中泛型类型参数的运行时类型。我建议阅读Java教程中有关类型擦除的章节以了解更多详细信息。
对此,一个流行的解决方案是将类型参数的Class传递给泛型类型的构造函数,例如。
class Foo<T> {
final Class<T> typeParameterClass;
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}
这是一个有效的解决方案:
@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>(){};)
我一直在寻找一种不向类路径添加额外依赖项的方法。经过一些调查,我发现只要你有一个泛型超类型,这是可能的。这对我来说是可以的,因为我正在使用一个具有通用层超类型的DAO层。如果这符合您的情况,那么这是IMHO最整洁的方法。
我遇到的大多数泛型用例都有某种泛型超类型,例如ArrayList<T>的List<T>或DAO<T>的GenericDAO<T>等。
纯Java解决方案
在Java运行时访问泛型类型一文解释了如何使用纯Java实现这一点。
@SuppressWarnings("unchecked")
public GenericJpaDao() {
this.entityBeanType = ((Class) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0]);
}
弹簧解决方案
我的项目使用的是Spring,它甚至更好,因为Spring有一个方便的实用方法来查找类型。这是对我来说最好的方法,因为它看起来最整洁。我想如果你不使用Spring,你可以编写自己的实用程序方法。
import org.springframework.core.GenericTypeResolver;
public abstract class AbstractHibernateDao<T extends DomainObject> implements DataAccessObject<T>
{
@Autowired
private SessionFactory sessionFactory;
private final Class<T> genericType;
private final String RECORD_COUNT_HQL;
private final String FIND_ALL_HQL;
@SuppressWarnings("unchecked")
public AbstractHibernateDao()
{
this.genericType = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), AbstractHibernateDao.class);
this.RECORD_COUNT_HQL = "select count(*) from " + this.genericType.getName();
this.FIND_ALL_HQL = "from " + this.genericType.getName() + " t ";
}
完整代码示例
有些人在评论中很难让这种方法发挥作用,所以我写了一个小应用程序来展示这两种方法。https://github.com/benthurley82/generic-type-resolver-test