正文

本文主要列举Java泛型与Kotlin泛型的基本知识,以及两者的区别。

什么泛型

泛型程序设计是程序设计的一种风格或或规范。简单的说就是该类型可变,在编写代码时可以根据情况设置不同的类型。因为泛型的可变性,很容易出现类型转换异常,Java与Kotlin在编译期间提供了泛型检测,帮助开发者在编译期间就能尽量避免此异常的出现。

Java泛型的基本知识

Java泛型主要用在类,接口,类方法。泛型仅在编译期间有效,编译完成后擦除泛型标记。

// 类
class ObjectA<T>{}
// 接口
interface InterfaceB<T>{}
// 方法
private <T> void fill(ArrayList<T> numbers) {}

泛型具有子类自动强转父类的功能,符合设计模式的里氏替换原则,例如:

class Parent{}class Child extends Parent{}// 指定泛型为Parent
ObjectA<Parent> o = new ObjectA<Parent>();
// 允许接收Parent的子类
o.add(new Child());

尽管泛型可以使用子类的类型,但是并不代表使用泛型的对象具有泛型的继承关系,例如:

private void fill(ObjectA<Parent> obj){}fill(new ObjectA<Parent>(););
// 该行代码会报错,错误提示为:Child不能转换为Parent
fill(new ObjectA<Child>());

由此可见泛型仅仅是提供了对象的类型判断而已,无法自动型变。

我们还可以限制泛型的范围,例如:

class ObjectA<T extends Parent>{public void add(T t){}
}

通过extends关键字表示,泛型只可以为Parent以及他的子类,设置其他泛型报错。通常情况下,extends可以缺省,例如:

class ObjectA<Parent>{}
class ObjectA<T extends Parent>{}

因为刚才我们提到了泛型具有自动向上强转的特性,所以两种代码作用相同,但是语义来看,extends的语义更强。但是某些情况下,设置了extends会有明显的不同,例如:

ArrayList<Parent> parents1 = new ArrayList<>();
ArrayList<? extends Parent> parents2 = new ArrayList<>();parents1.add(new Parent());
// 注意!!此行代码会报错
parents2.add(new Parent());Parent p1 = parents1.get(0);
Parent p2 = parents2.get(0);

?是Java泛型中的通配符,表示任何的类型。在指定泛型的时候,如果使用了extends关键字,表示集合内部只能添加Parent以及它的子类,但是Parent的子类我们只能选择一个,例如Parent有三个子类A,B,C,我们只能选择其中一个,但是具体是哪一个只能在运行中才能知道,所以Java干脆限制只能获取,不能添加。

与extends相对应的还有super关键字,它表示只能添加,而读取的类型是Object:

// suer关键字表示只可以输入Child以及它的父类
ArrayList<? super Child> children= new ArrayList<>();
children.add(new Child());
// 注意!!此行代码会报错
// Child child= children.get(0);
Child child= (Child) children.get(0);

很多资料都说super表示泛型为Child的父类,但是实际使用中并不是这样,他仍然是Child以及它的子类,因为所有类型的基类都是Object,那么super关键字就失去了意义,可能是因为这样的原因,super的作用目前与extends的范围一致,但是设计的思想是相反的,所以获取数据只能得到Object。

由此可以总结,extends限制的是输出类型的上限,super限制的输入类型下限。

Kotlin泛型与Java泛型的差异

Kotlin泛型与Java泛型大部分都是相同的,但是语言特性导致有部分差异。

一、Java泛型不可调用泛型的方法,Kotlin可以

// Java语法不可以直接调用泛型T的方法
private <T> void fill(ArrayList<T> numbers) {}
// Kotlin通过内联机制,可以使用泛型T的方法
inline fun <reified T> printGenerality(data: T) {println(T::class.java)
}

原因分析:泛型只在编译期间有效,运行期间会被擦除,所以泛型信息会消失,Java基于栈的形式调用方法得不到泛型的具体类型,Kotlin通过内联机制,编译期间是把方法直接添加到了对应的代码中,不存在栈调用的问题,所以可以通过上下文推导出泛型的具体类型。

友情提示:内联方法慎用return,会导致调用方直接返回。

二、Kotlin的泛型的型变

以之前的Java代码为例:

private void fill(ObjectA<Parent> obj){}fill(new ObjectA<Parent>(););
// 该行代码会报错,错误提示为:Child不能转换为Parent
fill(new ObjectA<Child>());

虽然Child继承Parent,但是Java泛型无法推导出两者的继承关系,但是Kotlin的泛型可以:

val list1 = ArrayList<Number>()
val list2 = ArrayList<Double>()
fill(list1)
fill(list2)private fun fill(list: List<Number>) {}

原因分析:Kotlin把泛型拆分为输入泛型和输出泛型,关键字为in和out,例如:

class ObjectA<in T, out E>(private val t: T, private val e: E) {  // 泛型T仅可以出现在输入方法,例如setfun set(t: T) {this.t = t}// 泛型E仅可以出现在输出方法,例如getfun get() = e
}

上面的代码指定了,泛型T为输入类型,表示T只能用在输入的位置,例如set方法,如果有getT方法则报错,泛型E规则与之相反。

Kotlin重写了List接口:

// 标记集合的类型为输出类型
public interface List<out E> : Collection<E>

但是ArrayList则将泛型E既当做输入类型,也当做输出类型:

public class ArrayList<E>

所以调用方法 fill(list: List)时,判断out泛型是否一致,而Double可以向上强转为Number,所以检查通过。

总结Koltin的泛型用in修饰,表示此泛型只可出现在输入位置,支持类型型变,泛型使用out修饰,表示此泛型只可以出现在输出位置,支持类型的逆变。

Java泛型与Kotlin泛型相关推荐

  1. kotlin 反射java类_Android Kotlin的Class、反射、泛型

    前言 最近在学习kotlin的反射的时候遇到了一些问题,特地记录一下. 正题 在Java中使用Class很常见的就是,xxx类.class,比如我们在startActivity的时候startActi ...

  2. java 泛型 t_Kotlin(2) 泛型与集合

    前言 以一个java老鸟的角度,如何去看 kotlin.Java源代码应该如何用Kotlin重构.如何正确学习kotlin并且应用到实际开发中.本文将会探究. 本文分两大块,重难点和潜规则. 重难点: ...

  3. kotlin泛型_Kotlin泛型

    kotlin泛型 In this tutorial, we'll be looking in Kotlin Generics and Variances. 在本教程中,我们将研究Kotlin的泛型和变 ...

  4. Kotlin泛型上界与扩展函数

    文章目录 泛型场景 泛型递归和链式调用 子类的泛型递归 直接使用父类 Kotlin的问题与方式 使用时必须指定类型的泛型的问题 Kotlin的方式 泛型场景 先由我们熟悉的Java说起,有时在使用泛型 ...

  5. 第8章 泛型 《Kotlin 项目实战开发》

    第8章 泛型 通常情况的类和函数,我们只需要使用具体的类型即可:要么是基本类型,要么是自定义的类.但是在集合类的场景下,我们通常需要编写可以应用于多种类型的代码,我们最简单原始的做法是,针对每一种类型 ...

  6. Kotlin学习:Kotlin泛型

    Kotlin 泛型 泛型,即 "参数化类型",将类型参数化,可以用在类,接口,方法上. 与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼. 声明 ...

  7. 泛型java 代码讲解_Java泛型详解

    2516326-5475e88a458a09e4.png 一,打破砂锅问到底 泛型存在的意义? 泛型类,泛型接口,泛型方法如何定义? 如何限定类型变量? 泛型中使用的约束和局限性有哪些? 泛型类型的继 ...

  8. Java这个高级特性-泛型,很多人还没用过!

    点击关注公众号,Java干货及时送达 泛型是 Java 的高级特性之一,如果想写出优雅而高扩展性的代码,或是想读得懂一些优秀的源码,泛型是绕不开的槛.本文介绍了什么是泛型.类型擦除的概念及其实现,最后 ...

  9. Java基础篇:泛型

    文章目录 1.为什么要有泛型 2.在集合中使用泛型 3.自定义泛型结构 4.泛型在继承上的体现 5.通配符的使用 1.为什么要有泛型 泛型:标签 泛型背后的核心思想就是:把一个集合中的内容限制为一个特 ...

最新文章

  1. python break
  2. 中国最好的电子商务平台,75商务网成功上线
  3. javafx窗体程序_JavaFX真实世界应用程序:EIZO CuratOR Caliop
  4. 马尔可夫蒙特卡罗 MCMC 原理及经典实现
  5. 图像处理中的卷积与模板
  6. 网上图书商城项目学习笔记-028编辑一级分类
  7. 代码回滚:Reset、Checkout、Revert的选择(转)
  8. javaScript高级程序设计.pdf 你不知道的JavaScript
  9. 自制操作系统软盘镜像的创建过程
  10. 高等数学学习笔记——第九讲——数列收敛的判定方法
  11. 致远oa系统报价_用友致远OA 系统 一般价钱?(公司60-70台左右的电脑)
  12. 【T+】畅捷通T+软件打印预览凭证或UFO生成报表 提示加载TBillOneCore.dll失败
  13. 当新建css样式时默认名,网页制作考题2
  14. 使用linux时电脑突然蓝屏,win7系统电脑突然蓝屏的原因的原因和解决方法介绍
  15. TCP/UDP端口列表(转)
  16. 全球 Hoster Point DNS 遭受重大 DDoS 攻击
  17. Carson带你学数据结构:手把手带你了解 ”图“ 所有知识!(含DFS、BFS)
  18. element 表格,实现选择的行变色
  19. 2019年,实现 React 动画的 5 种最常用方式
  20. 【网络】网络层协议——IP

热门文章

  1. LSH系列2:MinHashLSH——文档(集合)相似性
  2. 一二三四五,勾勒新华三云蓝图
  3. 基于CMAC小脑模型的数据训练和预测matlab仿真
  4. CANopen | 网络管理NMT01 - 节点上线报文与心跳报文
  5. 微信解锁新功能,堪称最强副业!
  6. 吃这些果蔬皮会致癌(转载)
  7. 如何给线程起名字呢?
  8. 魏则西事件之后,民营医疗的营销方式
  9. java毕业生设计作品测评网站计算机源码+系统+mysql+调试部署+lw
  10. 锁定运用计算机,终极:如何锁定您不知道的Win10键盘快捷键,带您轻松使用计算机,值得收藏...