javagenerics类型参数和对这些类型的操作

在寻找我最近遇到的有趣情况的答案时,我遇到了以下问题: 类型安全,Javagenerics和查询

我写了下面的课(清理了一下)

public abstract class BaseDaoImpl extends HibernateDaoSupport implements BaseDao { /** * Finds and Returns a list of persistent objects by a collection of criterions * @param criterions * @return list of persistent objects * @throws DBException */ @SuppressWarnings("unchecked") protected List findByCriteria(Collection criterions) throws DBException { try { DetachedCriteria criteria = DetachedCriteria.forClass(T.class); // BAD!!! for (Criterion criterion : criterions) { criteria.add(criterion); } List result = getHibernateTemplate().findByCriteria(criteria); return result; } catch (Exception e) { throw new DBException(T.class + " lookup by " + criterions + " failed", e); // BAD!!! } } } 

对于某些(可能是有充分理由), T.class会导致编译时错误。

我的第一个问题是为什么?

如果我将它更改为T.getClass()显然不应该编译 – 因为当“展开”或经过“擦除”时没有’T’ – 应该有一个静态方法,例如。 eclipse IDE提供以下编译消息:

无法从Object类型对非静态方法getClass()进行静态引用

我的第二个问题是为什么? 这个错误究竟意味着什么呢?

最后,以上述链接中指定的方式解决这个问题(或者更确切地说,我的解释)是最优化的方式吗?

 public abstract class BaseDaoImpl extends HibernateDaoSupport implements BaseDao, MyGenericHelper { /** * Finds and Returns a list of persistent objects by a collection of criterions * @param criterions * @return list of persistent objects * @throws DBException */ @SuppressWarnings("unchecked") protected List findByCriteria(Collection criterions) throws DBException { try { DetachedCriteria criteria = DetachedCriteria.forClass(getGenericClass()); // BAD!!! for (Criterion criterion : criterions) { criteria.add(criterion); } List result = getHibernateTemplate().findByCriteria(criteria); return result; } catch (Exception e) { throw new DBException(getGenericClass() + " lookup by " + criterions + " failed", e); // BAD!!! } } } public interface MyGenericHelper { public Class getGenericClass(); } 

谢谢!

无法访问T.class的原因是因为T在编译时被擦除,因此在运行时不存在获取类。

典型的黑客是制作工厂方法:

  public static  BaseDAOImpl createBaseDAO(Class klass) { return new BaseDAOImpl(klass); } 

然后在构造函数中将klass变量存储为字段,并在需要时引用它。

如果你想保留一个无参数的构造函数,你可以使用你的界面(我个人会使用受保护的抽象方法)。

  protected abstract Class getGenericClass(); 

编辑:在通用抽象超类的情况下,有几个选项。 一个是构造函数,然后让子类只需要调用它(没有一个无参数的构造函数)。 像这样的东西:

  protected BaseDAOImpl(Class klass) { //store the parameter in a field. } 

然后静态方法不相关,因为您必须创建子类。 当基于类可以返回正确的实现时,更多地使用静态工厂方法(因此您有工厂,而不仅仅是策略)。

为了完整起见,我应该指出,如果子类在扩展抽象类时声明generics,如下所示:

  public IntegerImpl extends BaseDAOImpl {} 

那么generics类型将保留在类中。 使用该课程可以获得非常难看的黑客攻击。 我试验过这个,它起作用了:

  (Class) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0] 

但它对inheritance层次结构做出了巨大的假设,如果它完全可以避免的话,不应该用于任何严重的事情,但是为了全面了解正在发生的事情,我将其包括在内。

对于某些(可能是有充分理由),T.class会导致编译时错误。

我的第一个问题是为什么?

在编译时,编译器不知道类型T(在这种情况下,它可以是Integer,String),不能支持T.class返回实际的类。

但是,在运行时,由于类型擦除 ,类型信息被删除

 Cannot make a static reference to the non-static method getClass() from 

类型对象

我的第二个问题是为什么? 这个错误究竟意味着什么呢?

Hm .. getClass()是类(非静态)成员方法,它需要一个对象。 T不是一个对象,它是一个类型,所以它失败了。 它们不会使它静态,因为已经有一个XXX.class关键字,您可以从中获取Class对象。