java泛型类型参数和这些类型的操作

标签 java hibernate generics spring

在寻找我最近遇到的一个有趣情况的答案时,我遇到了以下问题:Type safety, Java generics and querying

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

public abstract class BaseDaoImpl<T extends Serializable> extends HibernateDaoSupport implements BaseDao<T> {

    /**
     * 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<T> findByCriteria(Collection<Criterion> criterions) throws DBException {
        try {
            DetachedCriteria criteria = DetachedCriteria.forClass(T.class); // BAD!!!
            for (Criterion criterion : criterions) {
                criteria.add(criterion);
            }

            List<T> 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 给出以下编译消息:

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

我的第二个问题是为什么?这个错误实际上意味着什么?

最后,按照上面链接中指定的方式(或者更确切地说是我的解释)解决这个问题是最佳方法吗?

public abstract class BaseDaoImpl<T extends Serializable> extends HibernateDaoSupport implements BaseDao<T>, MyGenericHelper<T> {

    /**
     * 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<T> findByCriteria(Collection<MyCriterion> criterions) throws DBException {
        try {
            DetachedCriteria criteria = DetachedCriteria.forClass(getGenericClass()); // BAD!!!
            for (Criterion criterion : criterions) {
                criteria.add(criterion);
            }

            List<T> result = getHibernateTemplate().findByCriteria(criteria);
            return result;
        }
        catch (Exception e) {
            throw new DBException(getGenericClass() + " lookup by " + criterions + " failed", e); // BAD!!!
        }
    }
}

public interface MyGenericHelper<T extends Serializable>  {
    public Class<T> getGenericClass();
}

谢谢!

最佳答案

之所以无法访问T.class,是因为T在编译时被删除了,所以在运行时它并不存在来获取类。

解决这个问题的典型技巧是创建一个工厂方法:

 public static <T extends Serializable> BaseDAOImpl<T> createBaseDAO(Class<T> klass) {
       return new BaseDAOImpl<T>(klass);
 }

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

如果你想保留一个无参数构造函数,你可以使用你的接口(interface)(我个人只会使用 protected 抽象方法)。

 protected abstract Class<T> getGenericClass();

编辑:对于通用抽象父类(super class),有几个选项。一种是拥有构造函数,然后让子类只需调用它(通过不使用无参数构造函数)。像这样的事情:

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

那么静态方法不相关,因为您必须创建子类。当基于类可以返回正确的实现时,更多地使用静态工厂方法(这样你就有了一个工厂,而不仅仅是一个策略)。

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

 public IntegerImpl extends BaseDAOImpl<Integer> {}

然后泛型类型被保留在类中。使用这个类有一个非常丑陋的技巧。我对此进行了实验,并且有效:

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

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

关于java泛型类型参数和这些类型的操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1595826/

相关文章:

java - 在 Play 中使用 Guice : Injection possible for static fields only

java - 在 Java 枚举中使用范围的种类

java - 不支持从 varbinary 到 BLOB 的转换

hibernate - hibernate 并将@GeneratedValue与CockroachDB一起使用会导致SQLGrammarException

java - 如何在java中进行整数枚举声明

c# - 通用 C# 方法

循环到第二个客户端时出现 java.util.NoSuchElementException

java - 如何修复此 DataBinding 和 LiveData 代码?

c# 泛型无法将源类型转换为目标类型

c# - 为什么这在代码 'IResult<H>'