1. 类型投影(in
和 out
关键字)
- 原理:
in
关键字用于逆变(Contravariance)。它表示类型参数只能用作输入,即作为函数的参数类型。例如,interface Consumer<in T> { fun consume(t: T) }
,这里 T
是逆变的,意味着如果 A
是 B
的子类型,那么 Consumer<B>
是 Consumer<A>
的子类型。
out
关键字用于协变(Covariance)。它表示类型参数只能用作输出,即作为函数的返回类型。例如,interface Producer<out T> { fun produce(): T }
,如果 A
是 B
的子类型,那么 Producer<A>
是 Producer<B>
的子类型。
- 应用场景:
- 逆变:适用于只消费数据而不产生数据的场景,如
Comparator
接口,Comparator<in T>
可以接受 T
及其子类型的对象进行比较。
- 协变:适用于只产生数据而不消费数据的场景,如
List<out T>
可以安全地返回 T
或其子类型的元素。
2. 可空类型
- 原理:在 Kotlin 中,类型默认是不可空的。要表示一个类型可以为空,需要在类型后面加上
?
,如 String?
。这使得编译器可以在编译时检查空指针异常,避免运行时出现 NullPointerException
。
- 应用场景:当一个变量可能为
null
时,如从数据库读取可能为空的值,或者调用可能返回 null
的第三方库函数时,使用可空类型可以让代码更安全。
3. 类型推断
- 原理:Kotlin 编译器可以根据上下文自动推断变量的类型。例如,
val num = 10
,编译器可以推断 num
的类型为 Int
。在函数返回值类型推断中,如果函数体只有一个表达式,编译器可以推断出返回值类型。
- 应用场景:减少代码中的冗余类型声明,提高代码的可读性和简洁性。
4. 实现通用集合排序函数
fun <T : Comparable<T>?> sortNullableList(list: MutableList<T?>): MutableList<T?> {
return list.sortedWith(compareBy { it?.toString() }).toMutableList()
}
- 代码解释:
- 函数定义
fun <T : Comparable<T>?> sortNullableList(list: MutableList<T?>): MutableList<T?>
表示接受一个可变的可空元素列表,并返回一个排序后的可变可空元素列表。这里 T : Comparable<T>?>
约束了 T
必须是 Comparable
类型且可以为空。
list.sortedWith(compareBy { it?.toString() })
使用 compareBy
函数创建一个比较器,it?.toString()
确保在比较时,如果元素为 null
,将其转换为字符串 "null"
进行比较,从而避免空指针异常。
.toMutableList()
将排序后的不可变列表转换回可变列表返回。
5. 利用类型投影优化函数
fun <T : Comparable<T>?> sortNullableListWithProjection(list: MutableList<out T?>): MutableList<T?> {
val mutableList = list.toMutableList()
return mutableList.sortedWith(compareBy { it?.toString() }).toMutableList()
}
- 代码解释:
fun <T : Comparable<T>?> sortNullableListWithProjection(list: MutableList<out T?>): MutableList<T?>
函数接受一个协变的可空元素列表。这里使用 out
关键字表示 list
只能用于读取元素,符合类型投影规则。
val mutableList = list.toMutableList()
先将协变的列表转换为可变列表,以便后续进行排序操作。
- 后续的排序和返回操作与之前类似。这样处理既保证了类型安全,又利用了类型投影的特性。