在不将通用作为输入的情况下检索通用类型的 Class 个实例

Retrieve Class instance of Generic Type without taking the Generic as an input

我有一个 class:

public abstract class BaseDaoImpl<T extends BaseModel> implements BaseDao<T> {
}

我还使用注解来生成 SQL 查询(由于各种原因我无法使用 hibernate 等框架),例如 @Table & @Column

我希望能够检索 <T extends BaseModel> .class 实例,而不必将 T 作为方法的输入。

我想简单的替代方法是创建一个方法:

public void set(Class<T> clazz){}

但是我想尽可能避免这种情况,以尽可能简化我的代码。 这可能吗?

不幸的是,由于 type erasure,这是不可能的:您必须强制 类 在运行时提供元信息。我会做这样的事情(一个大型真实项目的改编片段)。

public abstract class AbstractBaseDao<T extends BaseModel> implements BaseDao<T>{

    public abstract Class<T> getType();
}

class ConcreteModel extends BaseModel {/*...*/}

class ConcreteDao extends AbstractBaseDao<ConcreteModel> {

    @Override
    public Class<ConcreteModel> getType() {
        return ConcreteModel.class;
    }
}

另一种方法是像这样定义自定义注释:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Type {

    Class value();
}

interface BaseDao<T extends BaseModel> { }

@Type(ConcreteModel.class)
public class ConcreteDao implements BaseDao<ConcreteModel> { }

...并在您的 DAO 的某些处理器中使用它,但这将需要一些额外的基础架构代码来注册所有带注释的 类。而且 - 再一次 - 你不能限制 type bounds within annotations.

虽然使用反射有点代码味,但是你可以得到你需要的信息:

Class<T> modelImplementationClass = (Class<T>)
   ((BaseModel)this.getClass().getGenericSuperclass())
      .getActualTypeArguments()[0];

反射是一种JavaAPI,允许您在运行时访问或修改方法、类、接口的行为。

通常应避免反射,因为它非常慢并且会通过揭示内部实现细节来破坏抽象。