Kotlin: Kotlin变量与类型系统深入解析
最后更新:2026-08-26
Kotlin 的类型系统不是 Java 的翻版——它用智能转换消灭强制转型,用 // 构建完整的类型代数,让类型系统为你工作而非与你对抗。
1. 你将学到
- 基本类型:、、、、
- 智能转换(Smart Cast): 之后直接用
- 显式转换: / ,无隐式窄化
- 、、 三大顶层类型
- 类型别名 提升可读性
2. 一个开发者的真实故事
(1) 痛点:Java 类型转换地狱
Bob 在维护 OrderProcessor 的 Java 代码时,到处是强制类型转换:、。一次漏写 instanceof 检查就导致 ClassCastException,生产环境每季度 3-5 次。
(2) Kotlin 智能转换的解法
KOTLIN
// Java: verbose and error-prone
if (obj instanceof Order) {
Order order = (Order) obj; // Must cast again
System.out.println(order.getId());
}
// Kotlin: smart cast eliminates the cast
if (obj is Order) {
println(obj.id) // No cast needed!
}
Kotlin 编译器在 检查后自动插入安全转换,Bob 再也没写过一行强制转型代码。
3. 基本类型
(1) 数值类型
Kotlin 没有暴露 Java 的原始类型(/),一切皆为对象,但编译器在 JVM 上优化为原始类型。
KOTLIN
val intValue: Int = 42 // 32-bit
val longValue: Long = 42L // 64-bit
val doubleValue: Double = 3.14 // 64-bit IEEE 754
val floatValue: Float = 3.14f // 32-bit IEEE 754
// Underscore for readability
val million = 1_000_000
val creditCard = 1234_5678_9012_3456L
val bytes = 0b11010010_01101001
| 类型 | 位数 | 范围 | 对应 Java |
|---|---|---|---|
| 8 | -128 ~ 127 | ||
| 16 | -32768 ~ 32767 | ||
| 32 | -2³¹ ~ 2³¹-1 | ||
| 64 | -2⁶³ ~ 2⁶³-1 | ||
| 32 | IEEE 754 | ||
| 64 | IEEE 754 |
(2) 非数值类型
KOTLIN
val bool: Boolean = true
val char: Char = 'A'
val str: String = "OrderProcessor"
// Character is NOT a number in Kotlin
// val code: Int = 'A' // ERROR
val code: Int = 'A'.code // OK: 65
val charFromCode: Char = 65.toChar() // OK: 'A'
4. 智能转换(Smart Cast)
Kotlin 编译器在类型检查后自动将变量转换为更具体的类型,无需手动转型。
(1) 基本智能转换
KOTLIN
fun process(input: Any) {
// After 'is' check, compiler smart casts
if (input is String) {
println(input.length) // Smart cast to String
}
// After '!is' check
if (input !is String) return
println(input.length) // Smart cast to String
}
// Smart cast with when
fun describe(obj: Any): String = when (obj) {
is String -> "String: ${obj.length} chars" // Smart cast
is Int -> "Int: ${obj.dec()}" // Smart cast
is List<*> -> "List: ${obj.size} items" // Smart cast
else -> "Unknown"
}
(2) 智能转换的限制
KOTLIN
// WARNING: smart cast may not work with var or custom getters
var obj: Any = "Hello"
if (obj is String) {
// obj could be changed between check and use
// println(obj.length) // WARNING in some cases
}
// Safe approach: use local val
val safeObj = obj
if (safeObj is String) {
println(safeObj.length) // OK - guaranteed stable
}
(3) Java cast vs Kotlin smart cast
| 维度 | Java | Kotlin |
|---|---|---|
| 语法 | 自动 | |
| 安全 | 运行时可能 CCE | 编译期保证 |
| 代码量 | 检查 + 转型两步 | 检查即转型一步 |
| 空安全 | 可能 NPE | 自动处理可空 |
5. 显式类型转换
Kotlin 不支持隐式窄化转换(如 → ),所有转换必须显式调用。
(1) 转换函数
KOTLIN
val longVal: Long = 42L
val intVal: Int = longVal.toInt() // Explicit narrowing
val doubleVal: Double = 3.99
val intFromDouble: Int = doubleVal.toInt() // Truncates: 3
// String to number
val parsed: Int = "42".toInt()
val parsedDouble: Double = "3.14".toDouble()
// Number to string
val strVal: String = 42.toString()
(2) 为什么没有隐式转换?
KOTLIN
// This would silently lose data - Kotlin prevents it
val longValue: Long = 2_147_483_648L // Exceeds Int.MAX_VALUE
// val intValue: Int = longValue // COMPILE ERROR
// Must be explicit about potential data loss
val intValue: Int = longValue.toInt() // OK but may overflow
| 转换类型 | Java | Kotlin |
|---|---|---|
| 宽化(Int→Long) | 隐式 | 显式 |
| 窄化(Long→Int) | 隐式(有风险) | 显式 |
| 字符串→数字 | ||
| 数字→字符串 |
6. 三大顶层类型
(1) 类型层次图
classDiagram
Any --> String
Any --> Int
Any --> Order
Any --> Unit
Any --> Nothing
class Any {
+equals()
+hashCode()
+toString()
}
class Unit {
<<singleton>>
}
class Nothing {
<<never returns>>
}
(2) Any:所有非空类型的父类
KOTLIN
// Any is the root of the Kotlin type hierarchy (like Object in Java)
val obj: Any = "Hello"
val obj2: Any = 42
val obj3: Any = Order("ORD-001", 299.99, "CONFIRMED")
// Any has only 3 methods: equals, hashCode, toString
// Use Any? for nullable root type
(3) Unit:函数的"无返回值"
KOTLIN
// Unit is like void in Java, but it's a real type
fun logOrder(order: Order): Unit { // Unit return is optional
println("Processing ${order.id}")
}
fun logOrder2(order: Order) { // Equivalent - Unit inferred
println("Processing ${order.id}")
}
// Unit is a singleton - can be used as a value
val unitValue: Unit = Unit
(4) Nothing:永远不会到达
KOTLIN
// Nothing means "this code never returns"
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
// Useful for Elvis operator with exceptions
val customer = order.customer ?: fail("Customer required")
// Infinite loop also returns Nothing
fun infiniteLoop(): Nothing {
while (true) { /* never returns */ }
}
(5) 三大顶层类型对比
| 类型 | 含义 | 使用场景 | Java 对应 |
|---|---|---|---|
| 所有非空类型的父类 | 通用引用 | ||
| 函数无有意义返回值 | 副作用函数 | ||
| 永远不会到达 | 异常抛出/死循环 | 无对应 |
7. 类型别名(typealias)
KOTLIN
// Simplify complex type signatures
typealias OrderMap = Map<String, List`<Order>`>
typealias OrderProcessor = (List`<Order>`) -> List`<String>`
typealias USD = Double
// Usage
val ordersByCustomer: OrderMap = mapOf(
"Alice" to listOf(Order("ORD-001", 299.99, "CONFIRMED"))
)
typealias Predicate`<T>` = (T) -> Boolean
val isHighValue: Predicate`<Order>` = { it.total > 10_000 }
// typealias does NOT create new types - just aliases
val map: OrderMap = ordersByCustomer // Same type
8. 完整示例:OrderProcessor 类型安全处理
KOTLIN
// ============================================
// OrderProcessor - Type-Safe Event Processing
// Feature: Process order events with smart cast
// ============================================
typealias OrderId = String
typealias USD = Double
sealed class OrderEvent {
data class Created(val orderId: OrderId, val total: USD) : OrderEvent()
data class Paid(val orderId: OrderId, val amount: USD) : OrderEvent()
data class Shipped(val orderId: OrderId, val trackingCode: String) : OrderEvent()
data class Cancelled(val orderId: OrderId, val reason: String) : OrderEvent()
}
fun handleEvent(event: OrderEvent): String = when (event) {
is OrderEvent.Created -> {
// Smart cast: event.orderId and event.total available
val threshold = 10_000
val priority = if (event.total > threshold) "VIP" else "STANDARD"
"Order ${event.orderId} created (\$${event.total} USD) -> $priority"
}
is OrderEvent.Paid -> {
val tax = event.amount * 0.08
"Order ${event.orderId} paid: \$${event.amount} USD (tax: \$$tax USD)"
}
is OrderEvent.Shipped ->
"Order ${event.orderId} shipped: ${event.trackingCode}"
is OrderEvent.Cancelled ->
"Order ${event.orderId} cancelled: ${event.reason}"
}
fun main() {
val events: List`<OrderEvent>` = listOf(
OrderEvent.Created("ORD-001", 299.99),
OrderEvent.Created("ORD-002", 15_000.00),
OrderEvent.Paid("ORD-001", 299.99),
OrderEvent.Shipped("ORD-001", "TRK-ABC123"),
OrderEvent.Cancelled("ORD-003", "Customer request")
)
events.forEach { event ->
val result = handleEvent(event)
println(result)
}
// Type check with smart cast
val anyEvent: Any = events[0]
if (anyEvent is OrderEvent.Created) {
println("\nSmart cast works: ${anyEvent.orderId} costs \$${anyEvent.total} USD")
}
}
输出:
TEXT
📖 仅展示
Order ORD-001 created ($299.99 USD) -> STANDARD
Order ORD-002 created ($15000.0 USD) -> VIP
Order ORD-001 paid: $299.99 USD (tax: $23.999200000000002 USD)
Order ORD-001 shipped: TRK-ABC123
Order ORD-003 cancelled: Customer request
Smart cast works: ORD-001 costs $299.99 USD
❓ 常见问题
Q Kotlin 的 Int 和 Java 的 int 是同一个东西吗?
A 在 JVM 上,Kotlin 的 Int 编译为 Java 的 int(原始类型),当需要对象时自动装箱为 Integer。开发者无需关心这个差异。
Q 智能转换什么时候不生效?
A 当变量是 且可能被并发修改,或有自定义 getter 时,编译器无法保证检查和使用的类型一致,智能转换不生效。
Q Nothing 类型有什么实际用途?
A 主要用于标记"永远不会返回"的函数(如抛异常),让编译器理解后续代码不可达,从而允许智能转换和 Elvis 运算符中使用。
Q typealias 会创建新类型吗?
A 不会。typealias 只是类型别名,编译器会替换为原始类型。需要真正的类型安全包装请用 inline class / value class。
Q 为什么 Kotlin 不支持隐式类型转换?
A 因为隐式窄化转换(如 Long→Int)会静默丢失数据,是 Bug 的常见来源。显式转换让开发者明确知道可能的数据丢失。
Q Any 和 Any? 有什么区别?
A Any 是所有非空类型的父类,Any? 是所有类型(包括可空)的父类。Any? = Any | null,是 Kotlin 类型系统的真正顶层。
📖 小节
- Kotlin 基本类型在代码中是对象,JVM 上编译器优化为原始类型
- 智能转换在 检查后自动转型,消灭了 Java 的强制类型转换
- 所有类型转换必须显式调用(/),无隐式窄化
- 是非空类型根, 是 void 的类型化, 表示永远不返回
- 为复杂类型提供可读别名,不创建新类型
- 数字下划线 提升大数可读性
📝 作业
- 基础题(难度⭐):声明不同类型的变量(Int、Double、Boolean、String),打印它们的类型 。提示:使用
- 进阶题(难度⭐⭐):写一个函数接收 ,用智能转换处理 String(打印长度)和 Int(打印平方值)。提示:
- 挑战题(难度⭐⭐⭐):用 和密封类设计一个订单事件类型系统,用 穷尽处理所有事件类型。提示:参考第 8 节完整示例