我想这样做:
Get "Class" object from generic type T
但反过来说。所以我想获得类对象的类型。在Pseudocode中我想做这样的事情:
public class ExampleClass {
public static final Class<?>[] classes = new Class[]{MyClass1.class,
MyClass2.class, MyClass3.class, MyClass4.class, MyClass5.class};
public void myMethod() {
for (Class<?> c : DataBaseConfigUtils.classes ) {
MyObjectDAO<c.getType(), Integer> myObjectDAO = getMyObjectDAO(c);
ArrayList<c.getType()> list = myObjectDAO.queryAll();
for (c.getType() element : list) {
processElement(element);
}
}
}
public <T> MyObjectDAO<T, Integer> getMyObjectDAO(Class<T> c) {
return doSomething(c);
}
}
但没有像Class.getType()
那样的东西。那么如何获取类对象的类型呢?
答案 0 :(得分:4)
这在Java中是不可能的。该类型仅在编译期间使用并被擦除。此信息不存在于字节码或运行时环境中。
https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
泛型被引入Java语言以提供更紧密的类型 在编译时检查并支持通用编程。至 实现泛型,Java编译器将类型擦除应用于:
- 如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。生成的字节码, 因此,只包含普通的类,接口和方法。
- 如有必要,插入类型转换以保护类型安全。
- 生成桥接方法以保留扩展泛型类型中的多态性。
类型擦除确保不会为参数化创建新类 类型;因此,泛型不会产生运行时开销。
答案 1 :(得分:1)
您的通用方法getMyObjectDAO
似乎回答了您自己的问题。如果在类型中有一个带通配符的变量,则只要需要引用代码中的类型,就可以使用通用的辅助方法。您可以将代码重构为:
public class ExampleClass {
public static final Class<?>[] classes = new Class[]{MyClass1.class,
MyClass2.class, MyClass3.class, MyClass4.class, MyClass5.class};
public void myMethod() {
for (Class<?> c : DataBaseConfigUtils.classes ) {
act(c);
}
}
private <T> void act(Class<T> c) {
MyObjectDAO<T, Integer> myObjectDAO = getMyObjectDAO(c);
ArrayList<T> list = myObjectDAO.queryAll();
for (T element : list) {
processElement(element);
}
}
public <T> MyObjectDAO<T, Integer> getMyObjectDAO(Class<T> c) {
return doSomething(c);
}
}
重要的是要意识到这一点的局限性。假设您有一个List<?>
类型的变量。虽然 可以使用私有通用帮助器方法,使您可以将其视为List<T>
并在代码中使用类型T
,但键入擦除意味着您可以& #39; t在运行时查询类型T
。所以以下所有都是非法的
if (T == String) { //do something; }
if (T.class == String.class) { //do something }
if (a instanceof T) { //do something }
通常的解决方法是将辅助方法的一个参数设为Class<T>
对象,因为可以执行
if (clazz == String.class) { //do something }
(请注意,如果T
本身是泛型类型,则无效。因为您无法编写List<String>.class
,例如。有一种称为超类型令牌的解决方法。)
由于您使用的对象是 Class
个对象,因此类型擦除不应该导致任何问题。
答案 2 :(得分:0)
例如:
ParameterizedType superclass = (ParameterizedType)getClass().getGenericSuperclass();
this.entityClass = (Class<T>) superclass.getActualTypeArguments()[0];
但是如果你想添加Generic类型,我想你有设计错误。最佳实践 - 您应该创建父(抽象)类或接口并在您的代码中使用它:
public abstract class ABaseEntity{
...
}
public class Child extends ABaseEntity{
...
}
使用您的BaseEntity创建基础dao将返回一些实体扩展您的ABaseEntity:
public class AbstarctDAO<T extends ABaseEntity, PK extends Serializable> {
@PersistenceContext
protected EntityManager em;
protected Class<T> entityClass;
protected AbstarctDAO() {
}
@PostConstruct
public void init(){
final ParameterizedType superclass = (ParameterizedType)getClass().getGenericSuperclass();
this.entityClass = (Class<T>) superclass.getActualTypeArguments()[0];
}
@Override
public T create(T object) throws Exception {
em.persist(object);
em.flush();
return object;
}
...
}
例外情况: 1。
AbstarctDAO dao = new AbstarctDAO();
try {
dao.create(new Child ());
}catch (Exception e){
}
2.
@ Stateless
@ Transactional
public class ChildDAO extends AbstarctDAO<Child , Long> {
@Transactional(Transactional.TxType.SUPPORTS)
public Child getChildByName(String name) {
...
return (Child)query.getSingleResult();
}
}