[英]How to get (generic) type from class object
我想這樣做:
但是反過來。 所以我想獲得類對象的類型。 在偽代碼中,我想做這樣的事情:
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()
。 那么如何獲得類對象的類型呢?
在Java中這是不可能的。 該類型僅在編譯期間使用並被擦除。 該信息在字節碼或運行時環境中不存在。
https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
Java語言引入了泛型,以在編譯時提供更嚴格的類型檢查並支持泛型編程。 為了實現泛型,Java編譯器將類型擦除應用於:
- 如果類型參數不受限制,則將通用類型中的所有類型參數替換為其邊界或對象。 因此,產生的字節碼僅包含普通的類,接口和方法。
- 必要時插入類型轉換,以保持類型安全。
- 生成橋接方法以在擴展的泛型類型中保留多態。
類型擦除可確保不會為參數化類型創建新的類; 因此,泛型不會產生運行時開銷。
您的通用方法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
的代碼,類型擦除意味着你無法查詢類型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
對象,因此類型擦除根本不會給您帶來任何問題。
例如:
ParameterizedType superclass = (ParameterizedType)getClass().getGenericSuperclass();
this.entityClass = (Class<T>) superclass.getActualTypeArguments()[0];
但是,如果您要添加泛型類型,我想您會遇到設計錯誤。 最佳實踐-您應該創建Parent(抽象)類或Interface並在代碼中使用它:
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();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.