学习主题:Kotlin 条件控制与智能类型转换
建议时长:2 天(每天约 1.5 小时)
学习目标:掌握 if / when 表达式的写法,理解 is 类型检查和智能转换机制
一、适合读者与学习目标
本文适合正在学习 Kotlin 的零基础或初学者。
如果你刚从 Java 转 Kotlin,不清楚 if 为什么能返回值、when 比 switch 强在哪里,或者经常看到 is 关键字但不懂"智能转换"是什么意思,可以通过本文系统掌握 Kotlin 条件控制的核心用法。
阅读前只需要:
- 了解 Kotlin 变量声明(val / var)
- 了解基本数据类型(Int、String、Boolean 等)
- 能用 Kotlin 运行 main 函数
二、为什么学这个
条件判断是程序的"决策大脑"。Android 开发中几乎每个功能都离不开它:
- 点击按钮后判断登录状态,跳转不同页面
- 根据网络返回的数据类型走不同解析逻辑
- 列表为空时显示占位图,否则显示数据
Kotlin 的 if / when 比 Java 更强大:它们本身能返回值,配合 is 类型检查还能自动"智能转换"类型,省去大量手动转型代码。
三、if 表达式
1. 基础用法(和 Java 一样)
kotlin
fun main() {
val score = 85
if (score >= 60) {
println("及格")
} else {
println("不及格")
}
}
这段代码和 Java 写法一致,逻辑也相同。但 Kotlin 的 if 不只是语句------它还是一个表达式,可以返回值。
2. if 作为表达式(重点)
Kotlin 没有 Java 的三元运算符 ? :,因为 if 本身就能返回值:
kotlin
fun main() {
val score = 85
val result = if (score >= 60) "及格" else "不及格"
println(result) // 输出:及格
}
说明:
if分支的最后一行就是返回值- 可以省略
return,直接赋值给变量 - 这彻底替代了 Java 的
score >= 60 ? "及格" : "不及格"
3. 多分支 if
kotlin
fun main() {
val score = 85
val grade = if (score >= 90) {
"优秀"
} else if (score >= 80) {
"良好"
} else if (score >= 60) {
"及格"
} else {
"不及格"
}
println(grade) // 输出:良好
}
每个分支的最后一行作为返回值。如果分支有多行代码,返回值就是最后一行。
4. 代码块中的返回值
kotlin
fun main() {
val a = 10
val b = 20
val max = if (a > b) {
println("a 更大")
a // 这一行是返回值
} else {
println("b 更大")
b // 这一行是返回值
}
println("最大值是 $max")
}
输出结果:
text
b 更大
最大值是 20
四、when 表达式
when 是 Kotlin 对 Java switch 的全面升级。它不光能匹配值,还能匹配类型、范围,而且同样可以作为表达式返回值。
1. 基础值匹配
kotlin
fun main() {
val day = 3
val dayName = when (day) {
1 -> "周一"
2 -> "周二"
3 -> "周三"
4 -> "周四"
5 -> "周五"
6 -> "周六"
7 -> "周日"
else -> "无效日期"
}
println(dayName) // 输出:周三
}
说明:
- 不需要写
break,匹配后自动跳出 else相当于 Java switch 的default- when 作为表达式时必须覆盖所有分支(通常用 else 兜底)
2. 多值合并匹配
kotlin
fun main() {
val day = 6
val type = when (day) {
1, 2, 3, 4, 5 -> "工作日"
6, 7 -> "周末"
else -> "未知"
}
println(type) // 输出:周末
}
多个值用逗号分隔,匹配任一即可。
3. 范围匹配(in / !in)
kotlin
fun main() {
val score = 85
val grade = when (score) {
in 90..100 -> "优秀"
in 80..89 -> "良好"
in 60..79 -> "及格"
in 0..59 -> "不及格"
else -> "分数不合法"
}
println(grade) // 输出:良好
}
in 用于判断值是否在某个范围内,!in 判断不在范围内。这对分数段、年龄段的判断非常简洁。
4. 类型匹配 + 智能转换(重点)
这是 when 最强大的用法------配合 is 做类型检查和自动转换:
kotlin
fun describe(obj: Any): String {
return when (obj) {
is Int -> "整数:${obj + 1}" // obj 自动转为 Int
is String -> "字符串长度:${obj.length}" // obj 自动转为 String
is Boolean -> if (obj) "真" else "假" // obj 自动转为 Boolean
else -> "未知类型"
}
}
fun main() {
println(describe(42))
println(describe("Hello Kotlin"))
println(describe(true))
}
输出结果:
text
整数:43
字符串长度:12
真
关键点:
is用来检查对象是否属于某个类型- 一旦
is检查通过,编译器自动将变量转换为该类型------这就是智能转换(smart cast) - 不需要像 Java 那样手动写
(String) obj或instanceof+ 强转
5. 无参数 when(替代 if-else if 链)
kotlin
fun main() {
val score = 85
when {
score >= 90 -> println("优秀")
score >= 80 -> println("良好")
score >= 60 -> println("及格")
else -> println("不及格")
}
}
不传参数时,每个分支就是一个布尔条件,相当于更清晰的 if-else if 链。
五、is 类型检查与智能转换 smart cast
1. 什么是智能转换
Kotlin 编译器会根据 is 检查的结果,自动将变量"转换"为对应类型,开发者无需手动强转。
kotlin
fun printLength(obj: Any) {
if (obj is String) {
// 编译器已经知道 obj 是 String 类型
// 可以直接调用 String 的方法,无需 (String) obj
println(obj.length)
}
}
同样的逻辑,Java 需要这样写:
java
void printLength(Object obj) {
if (obj instanceof String) {
System.out.println(((String) obj).length()); // 必须手动强转
}
}
2. 智能转换的多种场景
在 if 条件中:
kotlin
fun demo(x: Any) {
if (x !is String) return // 不是 String 就提前返回
println(x.length) // 编译器知道 x 一定是 String
}
在 when 条件中:
kotlin
fun getTypeInfo(value: Any): String = when (value) {
is Int -> "整数,值:$value"
is String -> "字符串,长度:${value.length}"
is List<*> -> "列表,元素个数:${value.size}"
else -> "其他类型"
}
在逻辑运算符 && 和 || 中:
kotlin
fun safeOperation(obj: Any): Int {
// && 右侧只有在左侧为 true 时才执行,此时 obj 已确定为 String
if (obj is String && obj.length > 0) {
return obj.length
}
return -1
}
3. 智能转换的前提条件
智能转换并非在所有情况下都生效。编译器要求判断完成后到使用之间,变量值不会改变。
kotlin
// ✅ val 局部变量 ------ 能智能转换
fun demo1(obj: Any) {
if (obj is String) {
println(obj.length) // OK
}
}
// ❌ var 属性 ------ 不能智能转换(可能被其他线程修改)
class MyClass {
var obj: Any = "hello"
fun test() {
if (obj is String) {
// println(obj.length) // ❌ 编译错误!obj 是 var,可能被修改
}
}
}
智能转换生效的条件:
| 变量类型 | 能否智能转换 | 原因 |
| --- | --- |
| 局部 val | ✅ 能 | 值不可变,编译器能保证类型不变 |
| 局部 var | ✅ 能(判断和使用之间未被修改时) | 编译器会检查中间是否有赋值 |
| 类的 val 属性 | ❌ 不能(除非有自定义 getter 且符合条件) | 可能被子类覆盖 |
| 类的 var 属性 | ❌ 不能 | 随时可能被修改 |
**解决方案:**用局部 val 快照。
kotlin
class MyClass {
var obj: Any = "hello"
fun test() {
val currentObj = obj // 快照到不可变局部变量
if (currentObj is String) {
println(currentObj.length) // ✅ 现在可以智能转换了
}
}
}
六、as 与 as? 类型转换
除了让编译器自动智能转换,Kotlin 也支持手动类型转换。
1. as(不安全转换)
kotlin
fun main() {
val obj: Any = "Hello"
val str: String = obj as String // 强转,如果类型不匹配会抛 ClassCastException
println(str.length)
}
2. as?(安全转换)
kotlin
fun main() {
val obj: Any = 123
val str: String? = obj as? String // 类型不匹配时返回 null,而不是抛异常
println(str) // 输出:null
}
as? 是安全转换:成功则返回转换后的值,失败则返回 null。通常配合 ?. 或 ?: 使用:
kotlin
fun printIfString(obj: Any) {
val str = obj as? String
println(str?.length ?: "不是字符串")
}
对比总结:
| 写法 | 含义 | 转换失败时 |
|---|---|---|
is |
类型检查(返回 Boolean) | 不转换,只返回 true/false |
as |
不安全强转 | 抛 ClassCastException |
as? |
安全强转 | 返回 null |
| 智能转换 | is 检查后编译器自动转换 |
编译期保证安全 |
七、常见错误
错误 1:when 表达式缺少 else
kotlin
// ❌ 编译错误:when 作为表达式,必须覆盖所有情况
val result = when (day) {
1 -> "周一"
2 -> "周二"
// 缺 else
}
// ✅ 正确
val result = when (day) {
1 -> "周一"
2 -> "周二"
else -> "未知"
}
错误 2:在 var 属性上依赖智能转换
kotlin
// ❌ 智能转换不生效
var message: Any = "hello"
if (message is String) {
// println(message.length) // 如果 message 是类属性(var),编译报错
}
错误 3:is 检查后仍然用 as 强转
kotlin
// ❌ 多余(但能运行)
if (obj is String) {
val str = obj as String // 不需要,obj 已经智能转换为 String
println(str.length)
}
// ✅ 简洁写法
if (obj is String) {
println(obj.length) // 直接使用
}
错误 4:when 中多了 break
kotlin
// ❌ Kotlin 的 when 不需要 break
when (day) {
1 -> {
println("周一")
break // ❌ 不用的
}
}
八、练习任务
练习 1:成绩评级
用 when 表达式写一个函数,输入分数(0-100),输出评级:
- 90~100:A
- 80~89:B
- 70~79:C
- 60~69:D
- 0~59:F
- 其他:无效分数
练习 2:类型分类器
写一个函数 classify(obj: Any): String,用 when + is 实现:
- Int → 输出"整数,平方为:{平方值}"
- String → 输出"字符串,反转后:{反转字符串}"
- Boolean → 输出"布尔值:{值}"
- List<*> → 输出"列表,元素个数:{size}"
- 其他 → 输出"未支持的类型"
练习 3:简单计算器
写一个函数 calculate(a: Int, op: String, b: Int): Int?,用 when 实现:
- op 为 "+" 返回 a + b
- op 为 "-" 返回 a - b
- op 为 "*" 返回 a * b
- op 为 "/" 返回 a / b(考虑除零情况)
- 其他运算符返回 null
提示:除法分支需要判断 b 是否为 0。
九、阶段小项目:猜数字游戏
综合运用 if / when 和 Day 1-2 的知识,写一个猜数字小游戏。
kotlin
import kotlin.random.Random
fun main() {
val target = Random.nextInt(1, 101) // 1 到 100 的随机数
var guess: Int
var attempts = 0
println("猜数字游戏开始!数字范围:1 ~ 100")
while (true) {
print("请输入你的猜测:")
guess = readlnOrNull()?.toIntOrNull() ?: continue // 非数字则跳过
attempts++
val hint = when {
guess > target -> "太大了,再小一点"
guess < target -> "太小了,再大一点"
else -> {
println("恭喜!猜对了,数字是 $target,你用了 $attempts 次")
break
}
}
println(hint)
}
}
请在自己的环境中运行这段代码,并尝试:
- 增加"最多 7 次"的尝试次数限制
- 游戏结束后,用 when 根据尝试次数输出评语(1~3 次:天才,4~6 次:不错,7 次:侥幸)
十、今日总结
知识清单
| 知识点 | 你掌握了吗? |
|---|---|
| if 作为表达式可以返回值 | □ |
| if 替代 Java 三元运算符 | □ |
| when 值匹配和多值匹配 | □ |
| when 范围匹配(in / !in) | □ |
| when 类型匹配 + is | □ |
| when 无参数用法 | □ |
| is 类型检查的写法 | □ |
| smart cast 智能转换的理解 | □ |
| 智能转换生效的前提条件 | □ |
| as 和 as? 的区别 | □ |
| val 快照解决 var 不能智能转换的问题 | □ |
下一步
Day 3-4 讲完了条件控制,Day 5-6 将进入 Kotlin 的循环语句(for / while)以及集合操作基础。建议先把本文的 3 个练习和猜数字项目独立完成后再继续。