Kotlin:如何在运行时中获取OneClass <t>中的实际泛型类型T.

时间:2018-01-09 02:45:47

标签: java generics types jvm kotlin

友! 我是Kotlin的绿手,现在这是一个问题。 现在我想在OneClass中获取泛型类型T,这里有一些外围代码。

// IDatabase.kt
package com.ra
abstract class IDatabase<T> { }
// Database1.kt
import kotlin.reflect.jvm.javaType
open class Database1<T>: IDatabase<T>() {
    val tClass = this::class.supertypes[0].arguments[0].type!!.javaType as Class<T>
}
// Database2.kt
import kotlin.reflect.jvm.javaType
open class Database2<T>: IDatabase<T>() {
    val tClass = this::class.supertypes[0].arguments[0].type!!.javaType as Class<T>
    // just wrap a `object` to confort the user
    companion object {
        fun <T> getInstance(): Database2<T> {
            return object: Database2<T>() {}
        }
    }
}

以下是主要功能,我测试了三种尝试获取泛型类型T的方法,结果在每个代码下的注释中。

fun main(args: Array<String>) {
    val database1 = Database1<String>()
    println(database1.tClass.canonicalName)
    /**
     * Exception in thread "main" java.lang.ClassCastException:
     * sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
     * at com.ra.Database1.<init>(Database1.kt:6)
     * at com.ra.MainKt.main(Main.kt:4)
     */

    val database2 = object: Database1<String>() {}
    print(database2.tClass.canonicalName)
    /**
     * java.lang.String
     */

    val database3 = Database2.getInstance<String>()
    println(database3.tClass.canonicalName)
    /**
     * Exception in thread "main" java.lang.ClassCastException:
     * sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
     * at com.ra.Database2.<init>(Database2.kt:6)
     * at com.ra.Database2$Companion$getInstance$1.<init>(Database2.kt:10)
     * at com.ra.Database2$Companion.getInstance(Database2.kt:10)
     * at com.ra.MainKt.main(Main.kt:19)
     */
}

正如你所看到的,只有一种成功的方式 - 方式2.但它根本不是很好。因为我想将它包装在一个静态函数中(如第3步那样),它再次失败。

所以这是我的问题:

  1. 为什么错误ClassCastException会发生?
  2. 有更好的方法可以解决问题吗?如果像C#的解决方案那样会很棒。
  3. 我知道问题的原因是JVM在编译时擦除了泛型类型,所以我想(只是好奇)什么时候可以改变?或者Kotlin或其他JVM语言可能会记录泛型类型信息?如果有任何请告诉我。我有足够的类型擦除...

1 个答案:

答案 0 :(得分:1)

它可以使用内联函数

package com.ba

import kotlin.reflect.KClass

abstract class IDatabase<T> { }

open class Database2<T: Any>(val tClass: KClass<T>) : IDatabase<T>() {
  // just wrap a `object` to confort the user
  companion object {
    inline fun <reified T: Any> getInstance(): Database2<T> = Database2(T::class)
  }
}

fun main(args: Array<String>) {
  val databaseString = Database2.getInstance<String>()
  println(databaseString.tClass)

  val databaseInt = Database2.getInstance<Int>()
  println(databaseInt.tClass)
}

输出

class kotlin.String
class kotlin.Int