0

我正在构建一个 ORM 以在 Kotlin 中与jasync-sql一起使用,并且有一个我无法解决的基本问题。我认为归结为:

T给定一个未具体化的类型参数,如何实例化一个类型类的实例T

众所周知的Spring Data 项目对此进行了管理,您可以在其CrudRepository<T, ID>接口中看到它,该接口使用类型参数进行参数化T,并公开返回 type 实例的方法T。我已经查看了源代码,但没有取得多大成功,但必须能够T在运行时实例化一个类型的类,尽管事实上它T正在被删除。

当我查看自己的AbstractRepository<T>抽象类时,我不知道如何获取对构造函数的引用,T因为它需要访问T::class.constructors可以理解的失败,除非T是具体类型。鉴于只能在内联函数的参数中使用具体类型,我对它是如何工作的有点迷茫?

4

2 回答 2

1

在 JVM 上,对象的运行时类型会被删除,但类上的泛型类型不会。因此,如果您正在使用具体的特化,您可以使用反射来检索类型参数:

import java.lang.reflect.*
​
abstract class AbstractRepository<T>
​
@Suppress("UNCHECKED_CAST")
fun <T> Class<out AbstractRepository<T>>.repositoryType(): Class<T> =
    generateSequence<Type>(this) {
        (it as? Class<*> ?: (it as? ParameterizedType)?.rawType as? Class<*>)
            ?.genericSuperclass
    }
        .filterIsInstance<ParameterizedType>()
        .first { it.rawType == AbstractRepository::class.java }
        .actualTypeArguments
        .single() as Class<T>
​
class IntRepository : AbstractRepository<Int>()
class StringRepository : AbstractRepository<String>()
interface Foo
class FooRepository : AbstractRepository<Foo>()
class Bar
class BarRepository : AbstractRepository<Bar>()
​
fun main() {
    println(IntRepository::class.java.repositoryType())
    println(StringRepository::class.java.repositoryType())
    println(FooRepository::class.java.repositoryType())
    println(BarRepository::class.java.repositoryType())
}
class java.lang.Integer
class java.lang.String
interface Foo
class Bar
于 2020-09-21T14:49:29.573 回答
0

在您自己的 CrudRepository 中,您可以添加一个带有内联 fun 的伴随对象,该对象负责通过将相应的类传递给它来实例化您的存储库。

class MyCrudRepository<T> protected constructor(
        private val type: Class<T>,
) {
    companion object {
        inline fun <reified T : Any> of() = MyCrudRepository(T::class.java)
    }

    fun createTypeInstance() = type::class.createInstance()
}
于 2020-09-21T13:29:46.147 回答