我想从通用类型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)
}
}
答案 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>
到构造函数并改为使用参数!