当前位置: 首页 > news >正文

Kotlin泛型约束

泛型类型约束简介

之前我们已经了解了,泛型可以接受任意类型的参数,使代码具有良好的复用性。现在,我们来学习泛型的另一个方面:类型约束(type bounds)
有时候,我们希望对泛型函数或类中允许的类型参数进行限制。例如,我们有一个泛型类 Storage<T>,但我们只想让它存储“书籍”类型的对象,而不需要创建另一个专门的类。这种情况下,就可以使用类型约束。


在类中使用类型约束

假设我们有以下泛型类:

class Storage<T>() {// 一些代码
}

解释: 这是一个通用存储类,可以保存任何类型的对象。

如果我们只希望这个类保存书籍,而“书籍”可以包括杂志、手册等,那么我们可以通过添加类型约束 T : Book 来限制只允许 TBook 或其子类:

class Storage<T : Book>() {// 一些代码
}

解释: 通过 T : Book,我们限制了泛型 T 必须是 Book 类型或其子类。这样我们就可以避免误地将非书籍类型存入该类中。


创建类并使用泛型类

open class Book {}
class Magazine : Book() {}
class Stone {}

解释: 我们创建了三个类:Book 是一个父类,Magazine 继承自 BookStoneBook 毫无关系。

然后我们尝试如下创建泛型类实例:

val storage1 = Storage<Book>()       // 合法
val storage2 = Storage<Magazine>()   // 合法(Magazine 是 Book 的子类)
val storage3 = Storage<Stone>()      // 编译错误

解释: 前两个实例是合法的,因为类型满足约束。第三个会报错:类型参数 Stone 不在它的界限内,这是编译时错误,有助于我们提前捕捉潜在问题。

默认情况下,所有泛型类型参数的上界是 Any?(允许空值)。也就是说 SomeGeneric<T> 默认等价于 SomeGeneric<T : Any?>

作为约束,可以使用类或接口,但不能试图让一个泛型类继承另一个(如 Storage<Magazine> : Storage<Book>),这是不允许的。


在函数中使用类型约束

我们也可以在泛型函数中使用类型约束,语法类似:

fun <T : Book> sortByDate(list: List<T>) { ... }

解释: 这个函数只接受泛型为 Book 或其子类的 List 参数。

假设有两个列表:

val listOne: List<Magazine> = listOf()
val listTwo: List<String> = listOf()sortByDate(listOne) // 合法,Magazine 是 Book 的子类
sortByDate(listTwo) // 错误,String 不是 Book 的子类

明确不可为空的类型(Definitely non-nullable types)

Kotlin 1.7 起支持:明确不可为空的类型,用于和 Java 的互操作。语法是:T & AnyTAny 的交集类型)。

前提:类型参数的上界必须是可空类型(如 Any?String?)。

示例 Java 接口:
public interface Game<T> {public T save(T x);@NotNullpublic T load(@NotNull T x);
}

解释: Java 中使用了 @NotNull 注解,说明 load() 不允许接收或返回 null。

Kotlin 中实现:
interface ArcadeGame<T1> : Game<T1> {override fun save(x: T1): T1override fun load(x: T1 & Any): T1 & Any // 正确用法// override fun load(x: T1): T1         // 编译失败
}

解释: 使用 T1 & Any 声明 T1 绝对不能为 null,从而符合 Java 中的 @NotNull 要求。


Kotlin 示例:Elvis 运算符风格函数

fun <T : String?> elvisLike(first: T, second: T & Any): T & Any = first ?: second

使用示例:

elvisLike<String>("", "123").length     // 结果为 0
elvisLike<String>("", null).length      // 编译错误,null 不能传给 non-null 参数
elvisLike<String?>(null, "123").length  // 结果为 3
elvisLike<String?>(null, null).length   // 编译错误,null 是非法参数

解释: elvisLike 函数模拟 Elvis 操作符行为:first 可能为 null,但 second 必须是非空的。这样可通过编译时确保安全。


多重约束(Multiple Bounds)

泛型变量可以有多个类型约束,但只有一个可以写在 <T> 中,其它的必须使用 where 子句。

示例:

fun <T> sortByDate(list: List<T>)where T : Book, T : Watchable<T> { ... }

解释: 类型参数 T 必须既是 Book 的子类,又实现 Watchable<T> 接口。

注意事项:

  • Kotlin 和 Java 一样 不支持多继承(类只能继承一个父类);

  • 但类可以实现多个接口,因此多个接口约束是允许的。


总结

  • 类型约束用于限制泛型参数类型。

  • 最常见的是 上界约束T : SomeType)。

  • 类型约束提高了代码的安全性和可读性。

  • Kotlin 支持:

    • 单个约束

    • 多个接口约束(使用 where 子句)

    • 明确不可为空类型(T & Any

这使得 Kotlin 泛型更加强大、类型安全且灵活。

http://www.lryc.cn/news/593011.html

相关文章:

  • NLP中情感分析与观念分析、价值判断、意图识别的区别与联系,以及四者在实际应用中的协同
  • RabbitMQ—事务与消息分发
  • espidf启用vTaskList方法
  • 使用MATLAB探索圆周率π的奇妙计算之旅
  • day25 力扣90.子集II 力扣46.全排列 力扣47.全排列 II
  • bws-rs:Rust 编写的 S3 协议网关框架,支持灵活后端接入
  • VBA 运用LISTBOX插件,选择多个选项,并将选中的选项回车录入当前选中的单元格
  • 关于NUC+雷达+倍福组网交换机是否完全足够的问题(是否需要一个路由器)
  • 软考 系统架构设计师系列知识点之杂项集萃(113)
  • WPF为启动界面(Splash Screen)添加背景音乐
  • 【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - snowNLP库实现中文情感分析
  • 标准文件和系统文件I/O
  • 车载刷写框架 --- 关于私有节点刷写失败未报引起的反思
  • 《命令行参数与环境变量:从使用到原理的全方位解析》
  • 移除debian升级后没用的垃圾
  • laravel RedisException: Connection refused优雅草PMS项目管理系统报错解决-以及Redis 详细指南-优雅草卓伊凡
  • 2025第15届上海国际生物发酵展:聚焦合成生物与绿色制造,共启生物经济新时代
  • Rust Web 全栈开发(十):编写服务器端 Web 应用
  • 医疗AI与融合数据库的整合:挑战、架构与未来展望(下)
  • 【C# in .NET】19. 探秘抽象类:具体实现与抽象契约的桥梁
  • xss的利用
  • CS231n-2017 Lecture2图像分类笔记
  • Kafka深度解析:架构、原理与应用实践
  • [论文阅读] 人工智能 + 软件工程 | 强化学习在软件工程中的全景扫描:从应用到未来
  • windows docker-02-docker 最常用的命令汇总
  • GEO营销:AI时代的搜索优化新赛道——从DeepSeek爆火看生成式引擎优化的崛起
  • Elasticsearch 重命名索引
  • LVS 集群技术实践:NAT 与 DR 模式的配置与对比
  • 牛客-倒置字符串
  • Go语言中的类型转换与类型推断解析