簡體   English   中英

如何從類對象獲取(通用)類型

[英]How to get (generic) type from class object

我想這樣做:

從通用類型T獲取“類”對象

但是反過來。 所以我想獲得類對象的類型。 在偽代碼中,我想做這樣的事情:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM