0

我有以下功能:

/**
 * 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 作为参数。无论如何我可以使用传入的泛型类型吗?

4

6 回答 6

2

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

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

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

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

然后你可以用类调用它:

findAll(String.class)

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

于 2012-06-21T21:02:14.557 回答
1

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

于 2012-06-21T21:03:32.907 回答
1

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

看一下这个例子:

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

于 2012-06-21T20:58:06.690 回答
1

不是真的,不。泛型是一个编译时特性。在运行时,您的 API 的调用者可以提供实体类型的任何实例,Class<T>因此您需要它在运行时可用以提供给休眠。编译器基本上没有能力为每个可能的方法构建一个单独的版本T,这是为了省略类参数而必须做的。

另外,Class是原始类型,您已经不正确地使用了泛型;)

于 2012-06-21T20:59:29.773 回答
1

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

于 2012-06-21T20:59:38.297 回答
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 编译器记录了编译时删除了哪些泛型。

于 2012-06-21T21:27:03.317 回答