6.1.4 Kotlin如何获得声明的泛型类型

虽然Java使用了类型擦除来实现泛型,但是它生成的class文件中还是保存了泛型相关的信息。这些信息被保存在class字节码常量池中,使用泛型的代码会生成一个signature签名字段,该signature签名字段指明了这个常量池的地址,因此从该常量池中能够获取到具体的类型。

跟Java一样,Kotlin也是通过类型擦除支持泛型的。

由于运行时被擦除,因此会带来一些影响。那么如何使用Kotlin来解决这些问题呢?下面列举一些常用的方法。

1.匿名内部类获得泛型信息

Java可以使用匿名内部类的方式获取泛型参数的类型。

执行结果如下:

     Generic1.Generic1$InnerClass<java.lang.Integer>
     class java.lang.Integer

Kotlin同样适用此方法。

执行结果如下:

     generic.Generic1.generic.Generic1$InnerClass<java.lang.Integer>
     class java.lang.Integer

2.反射获得泛型信息

Java利用反射获取运行时泛型参数的类型,子类可以获取父类泛型的具体类型。

在Kotlin中也同样适用此方法。

3.声明内联函数,使其类型不被擦除

Kotlin能够支持泛型数组,它们不会协变,例如:

     val array1 = arrayOf<Int>(1, 2, 3, 4)
     val array2 = arrayOf<String>("1", "2", "3", "4")

上述代码在定义两个数组时使用了arrayOf,它的源码如下:

可以发现arrayOf方法不仅使用inline修饰,还使用reified标记类型参数。于是,打印array1、array2的类型:

     println(array1.javaClass)
     println(array2.javaClass)

执行结果如下:

     class [Ljava.lang.Integer;
     class [Ljava.lang.String;

4.实例化类型参数代替类引用

再举一个Kotlin使用Gson的反序列化的例子,可以使用实例化类型参数T::class.java:

    inline fun <reified T : Any> Gson.fromJson(json: String): T = Gson().
fromJson(json, T::class.java)

小结一下获得泛型类型的几种方式:

· 前面两种方式是Java获取泛型类型的方式,Kotlin也适用。

· Kotlin的泛型方法要能够获取泛型类型,必须使用inline以及reified标记类型参数。