从非具体化类型参数实例化 类
Instantiating classes from non-reified type parameters
我正在构建一个 ORM 以在 Kotlin 中与 jasync-sql 一起使用,但有一个我无法解决的基本问题。我认为归结为:
How can one instantiate an instance of a class of type T
, given a
non-reified type parameter T
?
众所周知的 Spring Data project manages this,您可以在其 CrudRepository<T, ID>
接口中看到它,该接口使用类型参数 T
进行参数化,并公开 return 类型实例的方法T
。我查看了源代码但没有取得多大成功,但是 某处 它必须能够在运行时实例化 class 类型 T
,尽管事实上T
正在被删除。
当我查看自己的 AbstractRepository<T>
摘要 class 时,我不知道如何获取对 T
构造函数的引用,因为它需要访问 T::class.constructors
这可以理解地失败,除非 T
是具体化的类型。鉴于在内联函数的参数中只能使用具体化的类型,我有点不知道它是如何工作的?
在您自己的 CrudRepository 中,您可以添加一个带有内联乐趣的伴随对象,它负责通过将相应的 class.
传递给它来实例化您的存储库
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()
}
在 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
我正在构建一个 ORM 以在 Kotlin 中与 jasync-sql 一起使用,但有一个我无法解决的基本问题。我认为归结为:
How can one instantiate an instance of a class of type
T
, given a non-reified type parameterT
?
众所周知的 Spring Data project manages this,您可以在其 CrudRepository<T, ID>
接口中看到它,该接口使用类型参数 T
进行参数化,并公开 return 类型实例的方法T
。我查看了源代码但没有取得多大成功,但是 某处 它必须能够在运行时实例化 class 类型 T
,尽管事实上T
正在被删除。
当我查看自己的 AbstractRepository<T>
摘要 class 时,我不知道如何获取对 T
构造函数的引用,因为它需要访问 T::class.constructors
这可以理解地失败,除非 T
是具体化的类型。鉴于在内联函数的参数中只能使用具体化的类型,我有点不知道它是如何工作的?
在您自己的 CrudRepository 中,您可以添加一个带有内联乐趣的伴随对象,它负责通过将相应的 class.
传递给它来实例化您的存储库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()
}
在 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