Kotlin 泛型之类型擦除

  一. Java 泛型的优点

  泛型是 Java 5 的重要特性之一。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

  Java 泛型的优点包括:

  类型安全

  消除强制类型转换

  避免了不必要的装箱、拆箱操作,提高程序性能

  提高代码的重用性下面,以我的缓存框架RxCache中 Memory 接口为例:

  

 

  通过该接口的定义,能够看到使用泛型提高了代码的重用性。

  二. Kotlin 泛型

  Kotlin 基于 Java 6,因此 Kotlin 天生支持泛型。但是 Kotlin 的泛型有自己的特点。

  例如,对于扩展函数涉及到泛型的类,需要指定泛型参数:

  fun T : View T.longClick(block: (T) - Boolean) = setOnLongClickListener { block(it as T) }

  三. Java 通过类型擦除支持泛型

  Java 为了兼容性的考虑,采用类型擦除的机制来支持泛型。

  泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,这个过程被称为类型擦除。

  3.1 类型擦除

  由于类型擦除,List 和 List 在编译后都会变成 List。

  例如:

  ListString list1 = new ArrayList(); list1.add(kotlin); ListInteger list2 = new ArrayList(); list2.add(1);

  通过 javap -c 命令对代码进行反汇编:

  

 

  再对上述代码分别打印 list1、list2 的类型,再次验证一下类型擦除。

  System.out.println(list1.getClass()); System.out.println(list2.getClass());

  执行结果:

  class java.util.ArrayListclass java.util.ArrayList

  因此,List 在运行时并不知道泛型参数的类型。

  3.2 Java 数组并没有受到类型擦除的影响

  例如:

  String[] array1 = new String[5]; array1[0] = kotlin; Integer[] array2 = new Integer[5]; array2[0] = 1;

  通过 javap -c 命令对代码进行反汇编:

  

 

  从反汇编的角度可以看出,Java 数组并没有受到类型擦除的影响。

  再对上述代码分别打印 array1、array2 的类型,

  System.out.println(array1.getClass()); System.out.println(array2.getClass());

  执行结果:

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

  由此可见,数组在运行时可以获得它的类型。因为,Java 数组是协变的,所以 Java 数组不支持泛型。

  协变是在计算机科学中,描述具有父/子型别关系的多个型别通过型别构造器、构造出的多个复杂型别之间是否有父/子型别关系的用语。

  四. Kotlin 如何获得声明的泛型类型

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

  但是 Kotlin 的数组支持泛型,因此它们并不会协变。例如:

  val array1 = arrayOfInt(1, 2, 3, 4) val array2 = arrayOfString(1, 2, 3, 4)

  Kotlin的泛型在运行时被擦除了,会带来一些影响。如何解决 Kotlin 类型擦除带来的影响呢?办法肯定是有的。

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

  刚才定义的两个数组使用了 arrayOf ,通过查看 arrayOf 的源码:

  /** * Returns an array containing the specified elements. */public inline fun reified @PureReifiable T arrayOf(vararg elements: T): ArrayT

  它使用inline, 并且使用reified标记类型参数。

  打印 array1、array2 的类型:

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

  执行结果:

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

  4.2 实例化类型参数代替类引用

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

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

  总结:

  本文介绍了 Java 和 Kotlin 的泛型以及类型擦除,并介绍了如何获得声明的泛型类型。

  Kotlin 的泛型远不止这些,后续的文章会进一步介绍泛型的协变和逆变

  

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值