如何在 Kotlin 中获取泛型类型参数的类
Posted
技术标签:
【中文标题】如何在 Kotlin 中获取泛型类型参数的类【英文标题】:How to get class of generic type parameter in Kotlin 【发布时间】:2019-02-26 01:13:18 【问题描述】:我想从泛型类型T
中获取类属性。
我决定扩展至Any
,但出现错误。
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html#extension-properties
我有以下代码:
class FirebaseDBRepo<T : Any>(val child:String)
private var callback: FirebaseDatabaseRepositoryCallback<T>? = null
private val ref: DatabaseReference
private val listener = object : ValueEventListener
override fun onDataChange(dataSnapshot: DataSnapshot)
//T::class.java is showing the error cannot use t as reified type parameter use class instead
val gameDS = dataSnapshot.getValue(T::class.java)
callback!!.onSuccess(gameDS!!)
override fun onCancelled(databaseError: DatabaseError)
init
ref = FirebaseDatabase.getInstance().reference.child(child)
fun addListener(callback: FirebaseDatabaseRepositoryCallback<T>)
this.callback = callback
ref.addValueEventListener(listener)
fun removeListener()
ref.removeEventListener(listener)
【问题讨论】:
【参考方案1】:你只能在具体化的变量上获得类。同样的事情发生在 java 中,但消息略有不同:
public <T> void x()
T t = T.class.newInstance();
在 Java 中,您可以这样解决:
public <T> void x(Class<T> cls)
T t = cls.newInstance();
这同样适用于 Kotlin 和任何调用。在大多数情况下,您需要获取一个类实例。然而,Kotlin 支持使用关键字的具体泛型,但仅限于内联泛型函数。你可以传递一个类,但在函数中,使用 reified 关键字真的很容易。
因为你不能用具体的泛型声明一个类,这意味着这是无效的:
class SomeClass<reified T>
但它对内联函数有效,这意味着你可以这样做:
inline fun <reified T> someFunction()
所以你有两个选择。但是由于您扩展了侦听器,因此将泛型添加到函数的第一个选项不是一个选项。您不能使用泛型覆盖非泛型方法。它不会编译。
这留下了第二个选项,不幸的是它相当老套;将类传递给构造函数。所以它应该是这样的:
class FirebaseDBRepo<T : Any>(val child: String, private val cls: Class<T>)
现在,我不使用 Firebase,所以我不知道你会通过什么类,所以对于下一个示例,我只使用 String
。
Kotlin 支持某种类型的最小化,而无需使用原始类型。这个:
val t = FirebaseDBRepo<String>("", String::class.java)
可以缩短为:
val t = FirebaseDBRepo("", String::class.java)
两种情况下的推断类型都是FirebaseDBRepo<String>
。
【讨论】:
如果我使用val t = FirebaseDBRepo<String>("")
时 Kotlin 能够弄清楚将 cls
设置为什么,我会很高兴。特别是因为有时我有一个更像class FirebaseDBRepo<T : Any>(val child: T, private val cls: Class<T>)
的类定义。 Kotlin 可以从 child 中找出 T。在那种情况下,我希望能够做到FirebaseDBRepo("")
。【参考方案2】:
由于您在 JVM 上运行,因此类型擦除是一回事。 这意味着(简而言之),在编译期间,泛型被简单地忽略了。因此,您无法获得 T 的类,因为 JVM 甚至不知道您所说的“T”是什么意思。
在某些情况下,Kotlin 使用了一个巧妙的技巧来解决这个限制。当您使用内联函数时,编译器不会调用您定义的函数,而是将整个主体复制到您调用它的位置。这只能用于内联函数。不是课程。
有一个棘手的解决方法:只需添加private val classT: Class<T>
到构造函数并改用参数!
【讨论】:
以上是关于如何在 Kotlin 中获取泛型类型参数的类的主要内容,如果未能解决你的问题,请参考以下文章