简体   繁体   English

如何在Kotlin中获取泛型参数class

[英]How to get class of generic type parameter in Kotlin

I would like get the class property from a generic type T .我想从通用类型T获取 class 属性。 I've decided to extend to Any but I'm getting an error.我决定扩展到Any ,但出现错误。 https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html#extension-properties https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-any/index.html#extension-properties

I have the following code:我有以下代码:

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)
}

}

You can only get the class on reified variables. 您只能在已知的变量上获取该类。 The same thing happens in java, but with a slightly different message: 在java中也发生了同样的事情,但是消息略有不同:

public <T> void x(){
    T t = T.class.newInstance();
}

In Java, you'd solve this like: 在Java中,你可以解决这个问题:

public <T> void x(Class<T> cls){
    T t = cls.newInstance();
}

The same applies to Kotlin, and any calls. 这同样适用于Kotlin和任何电话。 You'd need to get a class instance in most cases. 在大多数情况下,您需要获取类实例。 However, Kotlin supports reified generics using a keyword, but only on inline generic functions. 但是,Kotlin使用关键字支持reified泛型,但仅支持内联泛型函数。 You could pass a class, but in functions, it's really easy just using the reified keyword. 你可以传递一个类,但在函数中,只需使用reified关键字就可以了。

As in you can't declare a class with reified generics, which means this is invalid: 因为你不能声明一个具有reified泛型的类,这意味着这是无效的:

class SomeClass<reified T>

But it is valid for inline functions, meaning you can do: 但它对内联函数有效,这意味着你可以这样做:

inline fun <reified T> someFunction()

So you have two options. 所以你有两个选择。 But since you extend a listener, the first option of adding the generics to the function isn't an option. 但是,由于您扩展了一个监听器,因此将该泛型添加到该函数的第一个选项不是一个选项。 You can't override a non-generic method with generics. 您不能使用泛型覆盖非泛型方法。 It won't compile. 它不会编译。

Which leaves the second option, which unfortunately is rather hackish; 这留下了第二种选择,不幸的是,这种选择相当苛刻; passing the class to the constructor. 将类传递给构造函数。 So it should look like this: 所以看起来应该是这样的:

class FirebaseDBRepo<T : Any>(val child: String, private val cls: Class<T>) {

Now, I don't use Firebase, so I have no clue what classes you'd pass, so for this next example, I just use String . 现在,我不使用Firebase,所以我不知道你要传递哪些类,所以对于下一个例子,我只使用String

Kotlin supports some type minimization without going over to raw types. Kotlin支持某种类型的最小化,而不需要转换为原始类型。 This: 这个:

val t = FirebaseDBRepo<String>("", String::class.java)

Could be shortened to this: 可以缩短到这个:

val t = FirebaseDBRepo("", String::class.java)

The inferred type in both cases is FirebaseDBRepo<String> . 两种情况下的推断类型都是FirebaseDBRepo<String>

Since you are running on the JVM, type erasure is a thing. 由于您在JVM上运行,因此键入擦除是一回事。 This means (in simplified terms), that during compilation, the generics are simply ignored. 这意味着(简单来说),在编译期间,简单地忽略泛型。 Therefore, you cannot get the class of T, as the JVM doesn't even know what you mean by "T". 因此,您无法获得T类,因为JVM甚至不知道“T”的含义。

Kotlin uses a clever trick to come around this limitation in some cases. 在某些情况下,Kotlin使用一个聪明的技巧来解决这个限制。 When you are using inline functions, the compiler does not call the function you defined, but instead, copies the whole body to the location where you called it. 当您使用内联函数时,编译器不会调用您定义的函数,而是将整个主体复制到您调用它的位置。 This can only be done for inline functions. 这只能用于内联函数。 Not classes. 不是课程。

There is a workaround tough: Just add private val classT: Class<T> to the constructor and use the parameter instead! 有一种解决方法很难:只需将private val classT: Class<T>到构造函数中,然后使用参数!

Maybe it is too late but you could get the memory address from the generic class.也许为时已晚,但您可以从通用 class 获得 memory 地址。

try to use:尝试使用:

object: GenericTypeIndicator<"T>() {} object: GenericTypeIndicator<"T>() {}

to get the memory address from ur generic value.从您的通用值中获取 memory 地址。

It looks then so:它看起来是这样的:

val gameDS = dataSnapshot.getValue(object: GenericTypeIndicator<"T">(){}

But you need to give your genericType without the ""但是你需要在没有 "" 的情况下提供你的 genericType

Maybe it is a solution for you.也许它是适合您的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM