【Kotlin精简】第7章 泛型
1 泛型
泛型即 “参数化类型”,将类型参数化,可以用在类,接口,函数上。与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。

1.1 泛型优点
- 类型安全:通用允许仅保留单一类型的对象。泛型不允许存储其他对象。
- 不需要类型转换:不需要对对象进行类型转换。
- 编译时检查:在编译时检查泛型代码,以便在运行时避免任何问题。
1.2 泛型声明
1.2.1 泛型类
interface List<T> {fun get(index: Int): T
}
泛型参数可在类中当普通类型使用。
1.2.2 泛型函数
fun <T> lastElement(list: List<T>): T { ... }
在 fun 关键字后声明 泛型形参,可在参数和返回值处声明使用。高阶函数的例子:
fun <T> List<T>.filter(pridicate: (T) -> Boolean): List<T> { ... }
1.2.3 泛型属性
val <T> List<T>.last: Tget() {return last()}
不管是泛型类、泛型函数还是泛型属性,在使用之前必然已经确定了类型。如泛型类在实例化时需要指定泛型类型,泛型函数在调用时必然已推导出泛型类型,并替换为确定的类型实参,泛型属性同理。
1.3 泛型约束
泛型(类型参数)是有边界的,可以给泛型设置边界:
interface NumberList<T: Number> {fun get(index: Int): T
}
不指定边界,则默认上边界为 Any?。如果希望非空,需要显示指定为 <T: Any> 。

2 泛型擦除
和 Java 一样,Kotlin 中的类型参数也会在运行时被擦除,就是说泛型实例的类型实参在运行时是不保留的。不过 Kotlin 可以通过类型参数实化的方式保留类型信息,需要使用内联函数。
由于泛型擦除,下面的普通方法是无法编译的:
fun <T> isA(obj: Any): Boolean {return obj is T
}
通过内联,下面代码可以通过编译:
inline fun <reified T> isA(obj: Any): Boolean {return obj is T
}
注意带 reified 类型参数的内联函数不能在 Java 代码中使用,普通内联函数在 Java 中可以像常规函数一样调用,而 reified 的类型参数需要额外处理将类型实参替换到字节码,是永远需要内联的。
实化类型参数也是有限制的,具体可以做:
- 类型转换和检查: 如 is 、as
- 使用反射: T::class
- 获取 java class: T::class.java
- 作为调用其他函数类型的实参。
3 变型
变型描述的是具有相同基础类型和不同类型参数的泛型类型之间的关系。这种关系可以是 协变的 或 逆变的。
先说说不变型,一个泛型类如 MutableList ,对任意两种类型实参 A、B,MutableList<A> 既不是 MutableList<B> 的子类型也不是它的超类型,则称 该类在该类型参数上是不变型的。Java 中的泛型类对所有类型参数都是不变型的。比如 Java 中你不能把一个 List<Ingeter> 实例传给形参是 List<Number> 的函数,即使 Integer 是 Number 的子类。
前面说的子父类型关系类似于类的子父类关系,比如 A 是 B 的子类,那么 A 是 B 的子类型,任一非空类型是其可空类型的子类型,比如 Person 是 Person? 的子类型,下面会说到 Kotlin 中借助协变使得 List<Int> 能够成为 List<Number> 的子类型,注意区分 子类 和 子类型。
Kotlin 中,比如上面自定义的 List 接口,也是不变型的,List<Int> 并不是 List<Number> 的子类型,因此你不能把一个 List<Int> 实例传给形参是 List<Number> 的函数。
注意 Kotlin 标准库中的 List 接口是可以的,因为是协变的,别和这里自定义的 List 搞混了
3.1 Out (协变)
对于 out 泛型,我们能够将使用子类泛型的对象赋值给使用父类泛型的对象。如果将上面的 List 接口定义改为:
interface List<out T> {fun get(index: Int): T
}
则称该 List 接口是协变的,如果基础类型间有子类型关系,则泛型类也具有相同的子类型关系。如 Int 是 Number 的子类型,则 上面定义的 List<Int> 也是List<Number> 的子类型。这样就可以将 一个 List<Int> 实例传给形参是 List<Number> 的函数了,简单来说协变——父类引用指向子类
当然,out 也不可以滥用 ,因为不安全,比如将一个 List<Int> 实例传入形参是 List<Any> 的函数,该函数像实例中添加 Any 类型的数据显然是错误的:
fun addMore(list: List<Any>) {list.add("abc")
}
addMore(listOf(1, 2, 3))
为了防止这种风险,如果类在该类型参数上是协变的,那么该类型参数只能出现在返回值位置,我们称之为 out 位置,即该泛型参数只读,编译器也会做这种检查。Kotlin 中的 List 接口就是协变的。集合可读、不可写,集合泛型协变。
3.2 In (逆变)
和协变相反,对于 in 泛型,我们可以将使用父类泛型的对象赋值给使用子类泛型的对象。如果一个泛型类 MyClass 是逆变的,则对于 有子类型关系的 A 和 B(A是B的子类型),则 MyClass<A> 是 MyClass<B> 的超类型。逆变——子类引用指向父类

例如 Comparable 接口:
public interface Comparable<in T> {public operator fun compareTo(other: T): Int
}
那么,Comparable<Any> 是 Comparable<Int> 的子类型。可以尝试理解成“能对 Any 类型进行比较”的比较器也能比较 Int 类型“。
类似的,这里的泛型参数只能出现在函数参数位置,我们称之为 in 位置。集合可读 Any 、可写,集合泛型逆变。
3.3 声明点变型
即声明泛型的地方产生变型。前面说的变型是针对类的所有实例的。而声明点变型则可以只针对某一实例变型。如:
val list: MutableList<out Int> = MutableList()
list.add(1,2) //报错
上面代码会将 list 变为只读的。
在 Java 中,没有类的变型声明,只通过声明点产生型变,如:
public interface Stream<T> {<R> Stream<R> map(Function<? super T, ? extends R> mapper);
}
与 Kotlin 不同的是,Java 通过 ? super T 产生逆变,? extends R 产生协变。
3.4 星号投影
List<*> 对应与 Java 中的 List<?>, 表示不确定的任意类型类型实参。可能是 Int,可能是Any,是确定的某种类型,但对使用者是未知的,因而不能生产该值,只能访问,当作 Any? 访问。注意和 List<Any?> 作区分。
4 小结
Kotlin的泛型概念和声明和Java相当接近。Kotlin的类型实参和Java一样会在运行期擦除。Kotlin可以通过类型参数实化保留运行时类型实参,需要借助内联函数。变型指的是具有相同基础类型和不同类型参数的泛型类型间的子类型关系。他指出了如果一个泛型类型的类型参数是另一个泛型类型类型参数的子类型,那么这个泛型类就是另一个泛型类的子类型或超类型。- 如果某个类在一个类型参数上声明成
协变的,那么该类型参数只能出现在out位置上。逆变相反。Java的泛型类都是不变型的。 - 声明点泛型只在声明处产生变型,
Java的变型都是该方式。Kotlin既可以使用声明点变型,也可以在整个泛型类上声明变型。 - 如果确切的类型实参是未知的或不重要的时候,可以使用
星号投影。
相关文章:
【Kotlin精简】第7章 泛型
1 泛型 泛型即 “参数化类型”,将类型参数化,可以用在类,接口,函数上。与 Java 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。 1.1 泛型优点 类型安全:通用允许…...
ElasticSearch与Lucene是什么关系?Lucene又是什么?
一. ElasticSearch 与 Lucene 的关系 Elasticsearch(ES)和Apache Lucene之间有密切的关系,可以总结如下: Elasticsearch构建于Lucene之上:Elasticsearch实际上是一个分布式的、实时的搜索和分析引擎,它构建…...
【算法练习Day40】打家劫舍打家劫舍 II打家劫舍 III
📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:练题 🎯长路漫漫浩浩,万事皆有期待 文章目录 打家劫舍打家劫舍 II打家劫…...
双十一运动健身好物推荐,这几款健身好物一定不要错过!
双十一购物狂欢节又要到了,又要到买买买的时候了!相信有很多想健身的小白还在发愁不知道买啥装备?别急,三年健身达人这就给你们分享我的年度健身好物! 第一款:南卡Runner Pro4s骨传导耳机 推荐理由&#…...
Angular异步数据流编程
1 目前常见的异步编程的几种方法 首先给出一个异步请求的实例: import {Injectable} from angular/core;Injectable({providedIn: root }) export class RequestServiceService {constructor() {}getData() {setTimeout(() > {let res zhaoshuai-lcreturn res…...
古典舞学习的独舞与群舞,古典舞的成品舞蹈教学大全
一、教程描述 本套教程的古典舞是很全面的,不仅有舞蹈动作分解教学,而且有成品舞的完整教学,同时提供独立的背景音乐文件,可以让你更快地学会古典舞。本套教程,大小30.54G,共有276个文件。 二、教程目录 …...
听GPT 讲Rust源代码--library/std(16)
题图来自 EVALUATION OF RUST USAGE IN SPACE APPLICATIONS BY DEVELOPING BSP AND RTOS TARGETING SAMV71[1] File: rust/library/std/src/sync/mpmc/select.rs 在Rust标准库中,rust/library/std/src/sync/mpmc/select.rs文件的作用是实现一个多生产者多消费者的选…...
计算机编程软件编程基础知识,中文编程工具下载分享
计算机编程软件编程基础知识,中文编程工具下载分享 给大家分享一款中文编程工具,零基础轻松学编程,不需英语基础,编程工具可下载。 这款工具不但可以连接部分硬件,而且可以开发大型的软件,象如图这个实例…...
微信小程序里怎么添加砍价活动
随着网络购物的普及,越来越多的消费者开始享受这种方便快捷的购物方式。而在这个大环境下,各种电商活动层出不穷,吸引了众多消费者的关注。而在这些活动中,砍价活动无疑是最受欢迎的一种。今天,我们就来聊一聊如何在小…...
如何在Python爬虫中使用IP代理以避免反爬虫机制
目录 前言 一、IP代理的使用 1. 什么是IP代理? 2. 如何获取IP代理? 3. 如何使用IP代理? 4. 如何避免IP代理失效? 5. 代理IP的匿名性 二、代码示例 总结 前言 在进行爬虫时,我们很容易会遇到反爬虫机制。网站…...
干货丨Linux终端常见用法总结(收藏)
一、前言 熟悉Linux终端的基础用法和常见技巧可以极大提高运维及开发人员的工作效率,笔者结合自身学习实践,总结以下终端用法供同行交流学习。 二、常见用法 1.快捷键 1.1.Alt. 在光标位置插入上一次执行命令的最后一个参数。 1.2.CtrlR 模糊搜索历…...
【RealTek sdk-3.4.14b】RTL8197FH-VG+RTL8812FR实现实现Host 网络和Guest 网络隔离以及各个连接终端间隔离功能
SDK 说明 ** Gateway/AP firmware v3.4.14b – Aug 26, 2019** Wireless LAN driver changes as: Refine WiFi Stability and Performance Add 8812F MU-MIMO Add 97G/8812F multiple mac-clone Add 97G 2T3R antenna diversity Fix 97G/8812F/8814B MP iss…...
【漏洞复现】Metinfo6.0.0任意文件读取漏洞复现
感谢互联网提供分享知识与智慧,在法治的社会里,请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现代码审计漏洞点 1.5、深度利用EXP编写 1.6、漏洞挖掘1.7修复建议 1.1、漏洞描述 漏洞名称:MetInfo任意文件…...
3.22每日一题(二重积分求平面区域面积)
先复习求平面积分的公式 注:面对平面积分直接使用二重积分对1求积分即可;所以只需要背二重积分的两个公式: 1、直角坐标下对1积分 2、极坐标下对1积分 xy-1是等轴双曲线!! 1、先画图定区域 2、选择先对x积分还是先对…...
Hadoop环境搭建
1 Hadoop集群环境搭建概述 所谓集群,就是一组通过网络互联的计算机,集群中的每一台计算机称作一个节点,Hadoop集群搭建就是在这个物理集群之上安装部署Hadoop相关的软件,然后对外提供大数据存储和分析等相关服务。 一个前提&…...
SpringBoot_mybatis-plus使用json字段
mybatis-plus使用json字段 1.前言2.方案分析2.1 为什么是json2.2 数据库的选择 3. 实战3.1 使用text字段(h2数据库)3.1.1 建表语句3.1.2 数据操作与查询 3.2 使用json字段(mysql数据库)3.2.1 建表语句3.2.2 数据操作与查询 4. 附录4.1 MySQL JSON索引用法4.2 mybatis-plus json…...
牛客出bug(华为机试HJ71)
Hj71:字符串通配符 描述 问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求: 实现如下2个通配符: *:匹配0个…...
第十一章 日志管理
第十一章 日志管理 1日志进程rsyslog 任务一 rsyslog 系统日志管理 关心问题 哪些程序产生的什么日志放到什么地方 任务一详解 1处理日志的进程 第一类 rsyslog 系统专职日志程序 处理绝大部分日志记录 系统操作有关的信息 如登录信息 程序启动关闭信息 错误喜喜 …...
灯串跨境外贸出口欧美CE认证和UL588报告周期解析
灯串灯具出口欧盟要做CE认证,CE认证需要做CE的两项检测,工作电压直流75V以上,交流50V以上 测试EMCLVD两项。 灯串LVD(安规)标准为: 欧洲EN 60598-2-20:2015 1.标记 2.结构 3.爬电距离和电气间隙 4.接线端子 5.外部接线和内…...
大数据中的分布式文件系统MapReduce的选择题
一 . 选择题 一. 单选题(共9题,49.5分) (单选题)下列传统并行计算框架,说法错误的是哪一项? A. 刀片服务器、高速网、SAN,价格贵,扩展性差上 B. 共享式(共享内存/共享存储),容错性好 C. 编程难度高 D. 实时、细粒度计算、计算密集型 正确答…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
React核心概念:State是什么?如何用useState管理组件自己的数据?
系列回顾: 在上一篇《React入门第一步》中,我们已经成功创建并运行了第一个React项目。我们学会了用Vite初始化项目,并修改了App.jsx组件,让页面显示出我们想要的文字。但是,那个页面是“死”的,它只是静态…...
CTF show 数学不及格
拿到题目先查一下壳,看一下信息 发现是一个ELF文件,64位的 用IDA Pro 64 打开这个文件 然后点击F5进行伪代码转换 可以看到有五个if判断,第一个argc ! 5这个判断并没有起太大作用,主要是下面四个if判断 根据题目…...
【PX4飞控】mavros gps相关话题分析,经纬度海拔获取方法,卫星数锁定状态获取方法
使用 ROS1-Noetic 和 mavros v1.20.1, 携带经纬度海拔的话题主要有三个: /mavros/global_position/raw/fix/mavros/gpsstatus/gps1/raw/mavros/global_position/global 查看 mavros 源码,来分析他们的发布过程。发现前两个话题都对应了同一…...
