正确使用Java Generics

时间:2012-06-21 20:54:26

标签: java generics

我有以下功能:

/**
 * Finds all entities of a certain type
 * @param <T> The type of the entity
 * @param entityType The class of the entity
 * @return A list of all the entities found, null if the entity is not in the database
 * or on error
 */
public <T> List<T> findAll(Class entityType) 
{
    javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
    cq.select(cq.from(entityType));
    return getEntityManager().createQuery(cq).getResultList();
}

你会注意到它是相当重复的。无论如何,我可以重构此函数,以便它不需要将Class作为参数。反正我是否可以使用传入的泛型类型?

6 个答案:

答案 0 :(得分:2)

不,你不能 - 直接。在几段中,我将向您展示解决问题的另一种方法。

Java泛型是通过 type erasure 实现的,这意味着所有类型信息都会在运行时被删除。当你的方法被调用时,它知道它应该返回一个List,但是在运行时没有什么可以告诉它它应该返回List<Foo>ArrayList构造函数不需要访问类对象来完成其工作;但是,你的代码确实如此。

解决这个问题的方法是只是传递类,因为这是一个泛型方法(而不是泛型类),你可以这样做。如果您将方法的声明更改为

public <T> List<T> findAll(Class<T> entityType)

然后你可以用课程来调用它:

findAll(String.class)

并且编译器将自动检测到它应该返回List<String>。它减少了冗余,但是通过从类中推断出类型参数而不是相反。这是解决此类问题的标准方法 - 它在Guava等库中显示出很多。

答案 1 :(得分:1)

创建“通用DAO”的标准做法是拥有一个可参数化的抽象类,并具有带特定参数的子类。这样,方法本身已经使用正确的类型进行参数化。

看看这个例子:

http://netbeans.org/projects/samples/sources/samples-source-code/content/samples/javaee/AffableBean/src/java/session/AbstractFacade.java

答案 2 :(得分:1)

不是,不。泛型是一个编译时功能。在运行时,API的调用者可以为entityType提供Class<T>的任何实例,因此您需要在运行时将其提供给hibernate。编译器无法为每个可能的T基本构建单独的方法版本,这是为了省略类参数所必须做的。

此外,Class是一种原始类型,您已经使用了不正确的泛型;)

答案 3 :(得分:1)

Java使用Type erasure,这意味着泛型类型参数在运行时不可用(在编译时用于确保代码对于类型是正确的)。这意味着要使用持久性,您需要显式传递该类,以便运行时可以弄清楚如何执行持久性(例如,持久对象所属的类)

答案 4 :(得分:1)

简单的答案是“不”。由于称为类型擦除的东西,所有参数化类型在运行时在编译的字节码中被视为Object.class。泛型类型仅在编译时使用,以防止您使用错误。

答案 5 :(得分:0)

您可以或多或少地在Scala中执行您所要求的操作。 (我不确定你是否可以使用scala,但仅供参考,这里是。)

object Main extends App{
    def findAll[T : Manifest]() : Array[T] = {
       var a = new Array[T](0)
       println(a.getClass)
       a
    }

    var result = findAll[String]()
    println(result.getClass)

    var result2 = findAll[Array[Int]]()
    println(result2.getClass)
}

通过使用隐式Manfiest,scala编译器会记录在编译时擦除泛型的内容。