Kotlin 泛型详解
时间:2026-08-13 | 作者:电竞小硕 | 阅读:0泛型,即 “参数化类型”,将类型参数化,可以用在类、接口、方法上。
与 Ja va 一样,Kotlin 也提供泛型,为类型安全提供保证,消除类型强转的烦恼。
声明一个泛型类:
class Box(t: T) {
var value = t
}
创建类的实例时,我们需要指定类型参数:
val box: Box = Box(1)
// 或者
val box = Box(1) // 编译器会进行类型推断,1 类型 Int,所以编译器知道我们说的是 Box。
以下实例向泛型类 Box 传入整型数据和字符串:
class Box(t : T) {
var value = t
}
fun main(args: Array) {
var boxInt = Box(10)
var boxString = Box("Runoob")
println(boxInt.value)
println(boxString.value)
}
输出结果为:
10
Runoob
定义泛型类型变量时,可以完整地写明类型参数。
如果编译器可以自动推定类型参数,也可以省略类型参数。
Kotlin 泛型函数的声明与 Ja va 相同,类型参数要放在函数名的前面:
fun boxIn(value: T) = Box(value)
// 以下都是合法语句
val box4 = boxIn(1)
val box5 = boxIn(1) // 编译器会进行类型推断
在调用泛型函数时,如果可以推断出类型参数,可以省略泛型参数。
以下实例创建了泛型函数 doPrintln,函数根据传入的不同类型做相应处理:
fun main(args: Array) {
val age = 23
val name = "runoob"
val bool = true
doPrintln(age) // 整型
doPrintln(name) // 字符串
doPrintln(bool) // 布尔型
}
fun doPrintln(content: T) {
when (content) {
is Int -> println("整型数字为 $content")
is String -> println("字符串转换为大写:${content.toUpperCase()}")
else -> println("T 不是整型,也不是字符串")
}
}
输出结果为:
整型数字为 23
字符串转换为大写:RUNOOB
T 不是整型,也不是字符串
泛型约束
我们可以使用泛型约束来设定一个给定参数允许使用的类型。
Kotlin 中使用 : 对泛型的类型上限进行约束。
最常见的约束是上界(upper bound):
fun > sort(list: List) {
// ……
}
Comparable
sort(listOf(1, 2, 3)) // OK。Int 是 Comparable 的子类型
sort(listOf(HashMap())) // 错误:HashMap 不是 Comparable> 的子类型
默认的上界是 Any。
对于多个上界约束条件,可以用 where 子句:
fun copyWhenGreater(list: List, threshold: T): List
where T : CharSequence,
T : Comparable {
return list.filter { it > threshold }.map { it.toString() }
}
型变
Kotlin 中没有通配符类型,它有两个其他的东西:声明处型变(declaration-site variance)与类型投影(type projections)。
声明处型变
声明处的类型变异使用协变注解修饰符:in、out,消费者 in, 生产者 out。
使用 out 使得一个类型参数协变,协变类型参数只能用作输出,可以作为返回值类型但是无法作为入参的类型:
// 定义一个支持协变的类
class Runoob(val a: A) {
fun foo(): A {
return a
}
}
fun main(args: Array) {
var strCo: Runoob = Runoob("a")
var anyCo: Runoob = Runoob("b")
anyCo = strCo
println(anyCo.foo()) // 输出 a
}
in 使得一个类型参数逆变,逆变类型参数只能用作输入,可以作为入参的类型但是无法作为返回值的类型:
// 定义一个支持逆变的类
class Runoob(a: A) {
fun foo(a: A) {
}
}
fun main(args: Array) {
var strDCo = Runoob("a")
var anyDCo = Runoob("b")
strDCo = anyDCo
}
星号投射
有时候会遇到这样一种情况:并不掌握类型参数的具体信息,但又希望它依然能被安全地使用。
这里说的“安全地使用”,本质上是指为泛型类型定义一种类型投射,并且要求该泛型类型的所有实例,都必须是这种投射的子类型。
对于这个问题, Kotlin 提供了一种语法, 称为 星号投射(star-projection):
- 假如类型定义为 Foo
, 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper ,Foo<> 等价于 Foo . 它表示, 当 T 未知时, 你可以安全地从 Foo< > 中 读取TUpper 类型的值. - 假如类型定义为 Foo
, 其中 T 是一个反向协变的类型参数, Foo<> 等价于 Foo . 它表示, 当 T 未知时, 你不能安全地向 Foo< > 写入 任何东西. - 假如类型定义为 Foo
, 其中 T 是一个协变的类型参数, 上界(upper bound)为 TUpper , 对于读取值的场合, Foo<*> 等价于 Foo , 对于写入值的场合, 等价于 Foo .
如果一个泛型类型里包含多个类型参数,那么每个类型参数都可以分别进行投射。
比如,类型定义为 interface Function 时,就可以出现下面几种星号投射:
- Function<*, String> , 代表 Function
; - Function
, 代表 Function ; - Function<, > , 代表 Function
.
注意: 星号投射与 Ja va 的原生类型(raw type)非常类似, 但可以安全使用
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- Kotlin基础语法:从包定义到函数声明的核心指南
- 时间:2026-08-27
-
- 协程进阶:协作、互斥与共享状态管理
- 时间:2026-08-27
-
- Kotlin 协程快速入门:核心定义、特性与实战指南
- 时间:2026-08-27
-
- Kotlin If表达式:告别嵌套,实现简洁赋值
- 时间:2026-08-27
-
- Kotlin流程控制精讲:for循环与区间(Range)的优雅结合
- 时间:2026-08-27
-
- Kotlin 流程控制:while 与 do/while 循环详解
- 时间:2026-08-27
-
- Kotlin/Js For Harmony:ArkTs开发工具套件详解
- 时间:2026-08-27
-
- Kotlin 类基础:深入解析主构造函数与次构造函数
- 时间:2026-08-27
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
