簡體   English   中英

如何確定泛型的類?

[英]How to determine the class of a generic type?

我正在創建一個通用類,並且需要使用一種方法來了解當前使用的通用類型的Class。 原因是我調用的方法之一期望將此作為參數。

例:

public class MyGenericClass<T> {
  public void doSomething() {
    // Snip...
    // Call to a 3rd party lib
    T bean = (T)someObject.create(T.class);
    // Snip...
  }
}

顯然,上面的示例不起作用,並導致以下錯誤:類型參數T的非法類文字。

我的問題是:有人知道這個的好選擇或解決方法嗎?

仍然存在相同的問題:常規信息在運行時被刪除,無法恢復。 一種解決方法是在靜態方法的參數中傳遞T類:

public class MyGenericClass<T> {

    private final Class<T> clazz;

    public static <U> MyGenericClass<U> createMyGeneric(Class<U> clazz) {
        return new MyGenericClass<U>(clazz);
    }

    protected MyGenericClass(Class<T> clazz) {
        this.clazz = clazz;
    }

    public void doSomething() {
        T instance = clazz.newInstance();
    }
}

很難看,但是可以用。

我只是被指出這種解決方案:

import java.lang.reflect.ParameterizedType;

public abstract class A<B> {
    public Class<B> g() throws Exception {
        ParameterizedType superclass =
            (ParameterizedType) getClass().getGenericSuperclass();

        return (Class<B>) superclass.getActualTypeArguments()[0];
    }
}

如果子類為A指定了具體類型,則此方法有效:

new A<String>() {}.g() // this will work

class B extends A<String> {}
new B().g() // this will work

class C<T> extends A<T> {}
new C<String>().g() // this will NOT work

不幸的是,克里斯托夫撰寫的解決方案僅在非常有限的情況下有效。 [編輯:如下所述,我不再記得我對這句話的推理了,這很可能是錯誤的:“請注意,首先,它僅在抽象類中起作用。”]下一個困難是g()僅對DIRECT有效A子類。 不過,我們可以解決此問題:

private Class<?> extractClassFromType(Type t) throws ClassCastException {
    if (t instanceof Class<?>) {
        return (Class<?>)t;
    }
    return (Class<?>)((ParameterizedType)t).getRawType();
}

public Class<B> g() throws ClassCastException {
    Class<?> superClass = getClass(); // initial value
    Type superType;
    do {
        superType = superClass.getGenericSuperclass();
        superClass = extractClassFromType(superType);
    } while (! (superClass.equals(A.class)));

    Type actualArg = ((ParameterizedType)superType).getActualTypeArguments()[0];
    return (Class<B>)extractClassFromType(actualArg);
}

實際上,這將在許多情況下起作用,但並非始終如此。 考慮:

public class Foo<U,T extends Collection<?>> extends A<T> {}

(new Foo<String,List<Object>>() {}).g();

這將引發ClassCastException ,因為這里的type參數根本不是ClassParameterizedType 這是TypeVariable T 因此,現在您將不得不嘗試找出T代表什么類型,以此類推。

我認為唯一合理的通用答案類似於Nicolas的初始答案-一般來說,如果您的類需要實例化在編譯時未知的其他某個類的對象,則該類的用戶需要傳遞該類文字(也許是工廠),而不是僅僅依賴泛型。

我找到了獲取通用對象的類的另一種方法

public Class<?> getGenericClass(){
         Class<?> result =null;
         Type type =this.getClass().getGenericSuperclass();

         if(type instanceofParameterizedType){
              ParameterizedType pt =(ParameterizedType) type;
              Type[] fieldArgTypes = pt.getActualTypeArguments();
              result =(Class<?>) fieldArgTypes[0];
        }
        return result;
  }

使用TypeTools可以很容易地解決T:

Class<T> t = (Class<T>) TypeResolver.resolveRawArguments(
                                MyGenericClass.class, getClass());

我將詳細介紹克里斯托夫的解決方案。

這是ClassGetter抽象類:

private abstract class ClassGetter<T> {
    public final Class<T> get() {
        final ParameterizedType superclass = (ParameterizedType)
            getClass().getGenericSuperclass();
        return (Class<T>)superclass.getActualTypeArguments()[0];
    }
}

這是一個靜態方法,使用上面的類來查找泛型的類型:

public static <T> Class<T> getGenericClass() {
    return new ClassGetter<T>() {}.get();
}

作為其用法的示例,您可以使用以下方法:

public static final <T> T instantiate() {
    final Class<T> clazz = getGenericClass();
    try {
        return clazz.getConstructor((Class[])null).newInstance(null);
    } catch (Exception e) {
        return null;
    }
}

然后像這樣使用它:

T var = instantiate();

公共類DatabaseAccessUtil {

EntityManagerFactory entitymanagerfactory;
EntityManager entitymanager;

public DatabaseAccessUtil() {
    entitymanagerfactory=Persistence.createEntityManagerFactory("bookmyshow");
    entitymanager=entitymanagerfactory.createEntityManager();
}

public void save  (T t) {
    entitymanager.getTransaction().begin();
    entitymanager.persist(t);
    entitymanager.getTransaction().commit();
}

public void update(T t) {
    entitymanager.getTransaction().begin();
    entitymanager.persist(t);
    entitymanager.getTransaction().commit();
}

public void delete(T t) {
    entitymanager.getTransaction().begin();
    entitymanager.remove(t);
    entitymanager.getTransaction().commit();
}

public Object retrieve(Query query) {
    return query.getSingleResult();
}
//call the method - retrieve(object,requiredclass.class)
public Object retrieve(Object primaryKey,class clazz) throws Exception {

    return entitymanager.find(clazz,primaryKey);    

}

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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