如何在 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&lt;String&gt;

【讨论】:

如果我使用 val t = FirebaseDBRepo&lt;String&gt;("") 时 Kotlin 能够弄清楚将 cls 设置为什么,我会很高兴。特别是因为有时我有一个更像class FirebaseDBRepo&lt;T : Any&gt;(val child: T, private val cls: Class&lt;T&gt;) 的类定义。 Kotlin 可以从 child 中找出 T。在那种情况下,我希望能够做到FirebaseDBRepo("")【参考方案2】:

由于您在 JVM 上运行,因此类型擦除是一回事。 这意味着(简而言之),在编译期间,泛型被简单地忽略了。因此,您无法获得 T 的类,因为 JVM 甚至不知道您所说的“T”是什么意思。

在某些情况下,Kotlin 使用了一个巧妙的技巧来解决这个限制。当您使用内联函数时,编译器不会调用您定义的函数,而是将整个主体复制到您调用它的位置。这只能用于内联函数。不是课程。

有一个棘手的解决方法:只需添加private val classT: Class&lt;T&gt; 到构造函数并改用参数!

【讨论】:

以上是关于如何在 Kotlin 中获取泛型类型参数的类的主要内容,如果未能解决你的问题,请参考以下文章

17.scala的泛型类

自定义泛型结构:泛型类泛型接口泛型方法

反射获取泛型类泛型方法

java如何获得泛型中的类

Java泛型:泛型类泛型接口和泛型方法

Java泛型:泛型类泛型接口和泛型方法