Skip to content

变量与类型系统

源:Kotlin Basic Types

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

虽然可以省略显式类型,但在以下场景建议手动标注:

  1. 公共 API 的返回值:为了代码的可读性和向后兼容性。
  2. 复杂的泛型初始化
  3. 延迟初始化时

空安全 (Null Safety) 核心特性

这是 Kotlin 对现代编程语言最大的贡献之一。它将“是否可为空”这一信息直接编码进了类型系统中。

类型区分

  • String:绝对不可为空。
  • String?:可以为空。

安全调用与 Elvis 操作符

kotlin
val length = name?.length // 如果 name 为空,则返回 null,不抛异常
kotlin
val len = name?.length ?: 0 // 如果左侧为 null,则取默认值 0
kotlin
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) 以优化性能。

自动装箱时机
  1. 可空类型Int? 必须装箱为 java.lang.Integer
  2. 泛型:在 List<Int> 中,Int 会被装箱。
  3. 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:它是逻辑完备性的重要保障。
  • 关注装箱:在高性能计算中注意可空基本类型的内存开销。