使注释可用于泛型类型

时间:2010-06-12 00:18:36

标签: java generics annotations

给出像

这样的通用界面
interface DomainObjectDAO<T>
{
   T newInstance();
   add(T t);
   remove(T t);
   T findById(int id);
   // etc...    
}

我想创建一个指定类型参数的子接口:

  interface CustomerDAO extends DomainObjectDAO<Customer> 
  {
       // customer-specific queries - incidental.
  }

实现需要知道实际的模板参数类型,但当然类型擦除手段在运行时不可用。我可以包含一些注释来声明接口类型吗?像

这样的东西
  @GenericParameter(Customer.class)
  interface CustomerDAO extends DomainObjectDAO<Customer> 
  {
  }

然后,实现可以从接口获取此批注,并将其用作运行时泛型类型访问的替代。

一些背景知识:

此接口使用JDK动态代理实现,如here所述。这个接口的非泛型版本运行良好,但使用泛型更好,而不必在子接口中创建方法只是为了指定域对象类型。泛型和代理处理大多数事情,但在运行时需要实际类型来实现newInstance方法等。

2 个答案:

答案 0 :(得分:7)

通过调用以下方法,可以找到Dao子接口(CustomerDAO)的实际类型参数:

import java.lang.reflect.ParameterizedType;

public static Class<?> getDomainClass(final Class<?> daoInterface) {
    ParameterizedType type = (ParameterizedType) daoInterface.getGenericInterfaces()[0];
    return (Class<?>) type.getActualTypeArguments()[0];
}

当您将其称为

Class<?> domainClass = getDomainClass(daoInterface);

使用daoInterface == CustomerDAO.class,您将获得domainClass == Customer.class

在我的实现中,DaoFactory执行此调用并使用domainClass作为DaoInvocationHandler的构造函数参数。

答案 1 :(得分:1)

  

实现需要知道实际的模板参数类型。

当然,CustomerDao隐式的任何实现都知道类型参数是Customer。它正在实施DomainObjectDAO<Customer>而不是DomainObjectDAO<T>

如果CustomerDao类扩展了泛型抽象类,并且该泛型抽象类需要知道T的实际类型,那么问题才会出现。但是你可以通过将T的Class对象(在本例中为Customer.class)作为构造函数参数传递给超类来处理它。