调用泛型类型的构造函数?

时间:2016-10-29 19:36:55

标签: java class generics inheritance constructor

我正在尝试为我的数据库创建自己的存储库,所以我尝试这样的事情:

@Override
public <T extends DatabaseObject> List<T> getList() {
    Cursor cursor = getCursor(somehowGetClassOfT(), null, null); //how to do this?
    //excess code removed, rest of function not relevant to question
    return list;
}

protected <T extends DatabaseObject> Cursor getCursor(Class<T> clazz, String selection, String[] selectionArgs) {
    DatabaseObject databaseObject = instantiateFromT(clazz); //how to do this?
    String tableName = databaseObject.getTableName();
    String[] projection = databaseObject.getProjection();
    String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER;
    Cursor cursor = database.query(
            tableName,                            
            projection,               
            selection,                             
            selectionArgs,                            
            null,                                     
            null,                                     
            sortOrder                                 
    );
    return cursor;
}

换句话说,我有许多扩展DatabaseObject的类,我希望能够动态地为它们构造一个Cursor。

我已经在DatabaseObject中定义了基本方法,例如获取表名,列名的String数组等,但由于我不能通过接口覆盖静态方法(对于像表名这样的东西),我必须实例化一个空白对象所以我可以用getter获取表名。

但是,我不确定如何实施:

  1. somehowGetClassOfT()。无论T是什么,我都希望将它传递给Cursor函数。

  2. instantiateFromT(clazz)。给定一些类,调用构造函数,以便我可以访问该对象的table / projection / sort字段。

  3. 或者通过使用我一直听到的“反射”来实现这一切吗?

1 个答案:

答案 0 :(得分:4)

泛型在运行时不具体化。由于信息不存在,您有两种解决方案:

  • 可以通过引入类
  • 的私有字段在编译时存储它
  • 您可以使用反射在运行时从实例中解析泛型类型。

这是一个带有私有字段T和构造函数的示例,从代码开始:

public abstract class MyRepository<T extends DatabaseObject> {

    private Class<T> type;

    public MyRepository(Class<T> type) {
      this.type = type;
    }

    public <T> List<T> getList() {
      Cursor cursor = getCursor(null, null); // how to do this?
      // excess code removed, rest of function not relevant to question
      return null;
    }

    protected <T extends DatabaseObject> Cursor getCursor(String selection, String[] selectionArgs) {
      DatabaseObject databaseObject = instantiateFromType(); // how to do this?
      String tableName = databaseObject.getTableName();
      String[] projection = databaseObject.getProjection();
      String sortOrder = databaseObject.getDefaultOrderColumn() + " " + DEFAULT_SORT_ORDER;
      Cursor cursor = database.query(
        tableName,
        projection,
        selection,
        selectionArgs,
        null,
        null,
        sortOrder);
      return cursor;
    }

    private DatabaseObject instantiateFromType() {
      try {
          T interfaceType = (T) type.newInstance();
          return interfaceType;
      }
      catch (Exception e) {
          // TODO to handle
       }         
    }
}

这里是你的DogRepository:

public class DogRepository extends MyRepository<Dog> {

    public DogRepository() {        
      super(Dog.class);
    }

}

使用Dog实现DatabaseObject:

public class Dog implements DatabaseObject{
   //todo
}

回答你的评论。

  

行DogRepository(Class类型),是否需要传入   作为论证的阶级?

不是不需要(抱歉,我读错了你的评论))。
更进一步,正如您可能注意到的那样,混凝土储存库的构造者是锅炉板代码 如果使用反射来解析DogRepository中使用的泛型背后的类,则不需要为它定义自定义构造函数。

例如,为了检索存储库中使用的类型,Spring使用JDK反射机制使用自己的库来完成这项工作:

Map<TypeVariable, Type> source = GenericTypeResolver.getTypeVariableMap(DogRepository.class);

Spring有它的库,因为它使用了很多反射 但在您的情况下,您也可以在不使用lib但使用自己的实用程序类的情况下完成工作。这是一个从存储库实例中解析泛型类型的示例。

DogRepository dogRepository = new DogRepository();
Class<?> typeClass = (Class<?>) ((ParameterizedType)   dogRepository.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
System.out.println("typeClass=" + typeClass );

使用反射来解析MyRepository构造函数中的有效泛型类型:

public abstract class MyRepository<T extends DatabaseObject> {

    private Class<T> type;

    public MyRepository() {
       type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }
   ...
 }

存储库具体类不再需要自定义构造函数:

public class DogRepository extends MyRepository<Dog> {

}