变量与类型系统
Kotlin 是一门静态类型语言。与 Java 相比,它在类型系统中引入了更多的约束(如空安全)和更高级的抽象(如 Nothing 类型),旨在通过编译器检查来消除运行时的潜在风险。
变量声明:只读与可变
Kotlin 强制开发者在声明变量时显式选择其可变性。
val (Read-only)
- 语义:只读引用。一旦初始化,其指向的引用不可更改。
- 底层实现:在 JVM 字节码中,
val变量会被编译为带final修饰符的字段。 - 注意:
val仅仅保证引用不变,但如果它指向的是一个可变对象(如MutableList),对象内部的内容依然可以改变。
var (Mutable)
- 语义:可变引用。可以多次赋值。
- 底层实现:编译为非
final字段,并生成相应的setter方法。
优先使用 val
在函数式编程和现代架构中,应尽可能使用 val 来保证状态的不可变性,从而减少多线程并发时的竞态风险。
类型推断 (Type Inference)
Kotlin 拥有强大的编译器类型推断能力。
kotlin
val count = 10 // 推断为 Int
val name = "Kotlin" // 推断为 String虽然可以省略显式类型,但在以下场景建议手动标注:
- 公共 API 的返回值:为了代码的可读性和向后兼容性。
- 复杂的泛型初始化。
- 延迟初始化时。
空安全 (Null Safety) 核心特性
这是 Kotlin 对现代编程语言最大的贡献之一。它将“是否可为空”这一信息直接编码进了类型系统中。
类型区分
String:绝对不可为空。String?:可以为空。
安全调用与 Elvis 操作符
kotlin
val length = name?.length // 如果 name 为空,则返回 null,不抛异常kotlin
val len = name?.length ?: 0 // 如果左侧为 null,则取默认值 0kotlin
val len = name!!.length // 告诉编译器“我担保它不为空”,失败则抛出 NPE (慎用)类型层次结构:Any, Unit 与 Nothing
Kotlin 拥有一个严密的顶级和底部类型系统。
Any:万物之源
Any 是所有非空类型的根(类似于 Java 的 Object)。Any? 则是所有类型的绝对根。
Unit:无意义的返回
Unit 类似于 Java 的 void,但它是一个真实的单例对象。如果一个函数没有显式返回值,它默认返回 Unit。
Nothing:永不返回的终点
Nothing 是所有类型的子类型。它表示“这个函数永远不会正常返回结果”。
- 应用场景:抛出异常的函数、死循环函数。
- 作用:帮助编译器进行代码流分析(例如,在
TODO()之后的代码会被标记为不可达)。
基本类型与装箱 (Boxing)
在 Kotlin 中,一切皆是对象(你可以调用 Int 的方法)。但在编译为 JVM 字节码时,编译器会尽可能使用原始类型 (Primitive Types) 以优化性能。
自动装箱时机
- 可空类型:
Int?必须装箱为java.lang.Integer。 - 泛型:在
List<Int>中,Int会被装箱。 - Any 引用:当基本类型被赋值给
Any时。
类型转换:显式与安全
Kotlin 不支持基本类型的隐式拓宽转换(如 Int 无法直接赋值给 Long)。
kotlin
val i: Int = 10
val l: Long = i.toLong() // 必须显式转换智能转换 (Smart Casts)
如果编译器通过 is 或非空检查能够确定变量的类型,它会自动进行类型转换,无需手动强制转换。
kotlin
if (obj is String) {
println(obj.length) // 自动识别为 String
}总结
- val 优先:构建不可变边界。
- 空安全是肌肉记忆:利用编译器消除 NPE。
- 理解 Nothing:它是逻辑完备性的重要保障。
- 关注装箱:在高性能计算中注意可空基本类型的内存开销。