首页 文章

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

提问于
浏览
34

Firebase的 snapshot.getValue() 预计会被调用如下:

snapshot?.getValue(Person::class.java)

但是我想用 Person 替换通过类声明传递给类的泛型参数,即

class DataQuery<T : IModel>

并使用该泛型参数执行以下操作:

snapshot?.getValue(T::class.java)

但当我尝试我得到一个错误说明

只能在类文字的左侧使用类

是否可以像在C#中那样为泛型参数提供类约束,或者是否可以使用其他语法来获取泛型参数的类型信息?

3 回答

  • 1

    对于具有泛型参数T的类,您无法执行此操作,因为您没有T的类型信息,因为JVM会删除类型信息 . 因此这样的代码不起作用:

    class Storage<T: Any> {
        val snapshot: Snapshot? = ...
    
        fun retrieveSomething(): T? {
            return snapshot?.getValue(T::class.java) // ERROR "only classes can be used..."
        }
    }
    

    但是,如果T的类型被内联并在内联函数中使用,则可以使其工作:

    class Storage {
        val snapshot: Snapshot? = ...
    
        inline fun <reified T: Any> retrieveSomething(): T? {
            return snapshot?.getValue(T::class.java)
        }
    }
    

    请注意,如果public,则内联函数只能访问该类的公共成员 . 但是你可以有两个函数变体,一个接收不是内联的类参数并访问私有内部,另一个内联辅助函数根据推断的类型参数进行相关:

    class Storage {
        private val snapshot: Snapshot? = ...
    
        fun <T: Any> retrieveSomething(ofClass: Class<T>): T? {
            return snapshot?.getValue(ofClass)
        }
    
        inline fun <reified T: Any> retrieveSomething(): T? {
            return retrieveSomething(T::class.java)
        }
    }
    

    您也可以使用 KClass 而不是 Class ,这样只有Kotlin的调用者可以使用 MyClass::class 而不是 MyClass::class.java

    如果您希望该类与泛型上的内联方法配合使用(意味着类 Storage 仅存储 T 类型的对象):

    class Storage <T: Any> {
        val snapshot: Snapshot? = ...
    
        inline fun <reified R: T> retrieveSomething(): R? {
            return snapshot?.getValue(R::class.java)
        }
    }
    

    内联函数中指定类型的链接:https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters

  • 33

    你需要的是你的通用参数的reified修饰符,你可以在这里阅读它 . https://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters所以,如果你这样做:

    inline fun <reified T : Any>T.logTag() = T::class.java.simpleName
    

    您将获得实际调用者类的名称,而不是“对象” .

  • 18

    你可以得到这样的类类型

    snapshot?.getValue((this.javaClass
                            .genericSuperclass as ParameterizedType)
                            .actualTypeArguments[0] as Class<T>)
    

相关问题