简体   繁体   English

如何从类对象获取(通用)类型

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

I would like to do this: 我想这样做:

Get "Class" object from generic type T 从通用类型T获取“类”对象

but the other way round. 但是反过来。 So I would like to get the type of class objects. 所以我想获得类对象的类型。 In Pseudocode I want to do something like this: 在伪代码中,我想做这样的事情:

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);
    }
}

But there is nothing like Class.getType() . 但是没有像Class.getType() So how to get the type of a class object? 那么如何获得类对象的类型呢?

This is not possible in Java. 在Java中这是不可能的。 The type is used only during the compilation and is erased. 该类型仅在编译期间使用并被擦除。 This information is not present in the bytecode or in the runtime environment. 该信息在字节码或运行时环境中不存在。

https://docs.oracle.com/javase/tutorial/java/generics/erasure.html https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. Java语言引入了泛型,以在编译时提供更严格的类型检查并支持泛型编程。 To implement generics, the Java compiler applies type erasure to: 为了实现泛型,Java编译器将类型擦除应用于:

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. 如果类型参数不受限制,则将通用类型中的所有类型参数替换为其边界或对象。 The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods. 因此,产生的字节码仅包含普通的类,接口和方法。
  • Insert type casts if necessary to preserve type safety. 必要时插入类型转换,以保持类型安全。
  • Generate bridge methods to preserve polymorphism in extended generic types. 生成桥接方法以在扩展的泛型类型中保留多态。

Type erasure ensures that no new classes are created for parameterized types; 类型擦除可确保不会为参数化类型创建新的类; consequently, generics incur no runtime overhead. 因此,泛型不会产生运行时开销。

Your generic method getMyObjectDAO seems to answer your own question. 您的通用方法getMyObjectDAO似乎可以回答您自己的问题。 If you have a variable with a wildcard in the type, you can use a generic helper method whenever you need to refer to the type in the code. 如果您的变量类型中带有通配符,则在需要在代码中引用该类型时,都可以使用泛型帮助器方法。 You can refactor your code into this: 您可以将代码重构为:

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);
    }
}

It is important to be aware of the limitations of this. 重要的是要意识到这一点的局限性。 Suppose you have a variable of type List<?> . 假设您有一个类型为List<?>的变量。 While it is possible to use a private generic helper method that will enable you to treat it as a List<T> and use the type T in code, type erasure means that you can't query the type T at runtime. 虽然可以使用私人通用的辅助方法将使你能够把它作为一个List<T>和使用类型T的代码,类型擦除意味着你无法查询类型T在运行时。 So all of the following are illegal 所以以下所有都是非法的

if (T == String) { //do something; }

if (T.class == String.class) { //do something }

if (a instanceof T) { //do something }

The usual workaround for this is to make one of the arguments to the helper method a Class<T> object, because you can do 通常的解决方法是将辅助方法的参数之一设为Class<T>对象,因为您可以

if (clazz == String.class) { //do something }

(Note that this will not work if T is itself a generic type, because you cannot write List<String>.class , for example. There is a workaround called super type tokens for this.) (请注意,如果T本身是泛型类型,则这将不起作用,因为例如您不能编写List<String>.class 。为此有一种解决方法,称为超类型令牌。)

Since the objects you are using are Class objects, type erasure should not cause you any problems at all. 由于您使用的对象 Class对象,因此类型擦除根本不会给您带来任何问题。

For example: 例如:

ParameterizedType superclass = (ParameterizedType)getClass().getGenericSuperclass();
    this.entityClass = (Class<T>) superclass.getActualTypeArguments()[0];

But if you want to add as type Generic I suppose you have design errors. 但是,如果您要添加泛型类型,我想您会遇到设计错误。 Best Practice for it - You should create Parent (abstract) class or Interface and use it in your code: 最佳实践-您应该创建Parent(抽象)类或Interface并在代码中使用它:

public abstract class ABaseEntity{
...
}
public class Child extends ABaseEntity{
...
}

Create base dao with your BaseEntity whiche will be return some entities extended you 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;
    }
...
}

Excecution example: 1. 执行示例: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