我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
我有一个泛型类,Foo<T>。在Foo的一个方法中,我想获取T类型的类实例,但我无法调用T.class。
使用T.class绕过它的首选方法是什么?
当前回答
我一直在寻找一种不向类路径添加额外依赖项的方法。经过一些调查,我发现只要你有一个泛型超类型,这是可能的。这对我来说是可以的,因为我正在使用一个具有通用层超类型的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
其他回答
你不能这样做,因为类型删除。另请参阅堆栈溢出问题Java泛型-类型擦除-何时发生以及发生什么。
比其他人建议的类更好的方法是传入一个对象,该对象可以执行您对类所做的操作,例如创建一个新实例。
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>());
很多人不知道这个把戏!事实上,我今天刚找到它!它就像一个梦!请查看以下示例:
public static void main(String[] args) {
Date d=new Date(); //Or anything you want!
printMethods(d);
}
public static <T> void printMethods(T t){
Class<T> clazz= (Class<T>) t.getClass(); // There you go!
for ( Method m : clazz.getMethods()){
System.out.println( m.getName() );
}
}
如果要扩展或实现任何使用泛型的类/接口,则可以获得父类/接口的泛型类型,而不必修改任何现有类/接口。
可能有三种可能性,
案例1当您的类正在扩展使用泛型的类时
public class TestGenerics {
public static void main(String[] args) {
Type type = TestMySuperGenericType.class.getGenericSuperclass();
Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
for(Type gType : gTypes){
System.out.println("Generic type:"+gType.toString());
}
}
}
class GenericClass<T> {
public void print(T obj){};
}
class TestMySuperGenericType extends GenericClass<Integer> {
}
案例2当类实现使用泛型的接口时
public class TestGenerics {
public static void main(String[] args) {
Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
for(Type type : interfaces){
Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
for(Type gType : gTypes){
System.out.println("Generic type:"+gType.toString());
}
}
}
}
interface GenericClass<T> {
public void print(T obj);
}
class TestMySuperGenericType implements GenericClass<Integer> {
public void print(Integer obj){}
}
案例3当您的接口扩展使用Generics的接口时
public class TestGenerics {
public static void main(String[] args) {
Type[] interfaces = TestMySuperGenericType.class.getGenericInterfaces();
for(Type type : interfaces){
Type[] gTypes = ((ParameterizedType)type).getActualTypeArguments();
for(Type gType : gTypes){
System.out.println("Generic type:"+gType.toString());
}
}
}
}
interface GenericClass<T> {
public void print(T obj);
}
interface TestMySuperGenericType extends GenericClass<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>(){};)