如何在Kotlin中获取泛型类型参数的类

时间:2018-09-21 15:29:06

标签: android generics firebase-realtime-database kotlin

我想从通用类型T获取class属性。 我决定扩展到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)
}

}

2 个答案:

答案 0 :(得分:8)

您只能获得有关归一化变量的类。在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>

答案 1 :(得分:3)

由于您正在JVM上运行,因此类型擦除是一件很重要的事情。 这意味着(以简化的方式),在编译期间,泛型将被简单地忽略。因此,您无法获得T的类,因为JVM甚至都不知道T的含义。

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

有一个艰难的解决方法:只需添加private val classT: Class<T> 到构造函数并改为使用参数!