Kotlin 条件判断 if / when 与智能转换 smart cast

学习主题: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) objinstanceof + 强转

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)
    }
}

请在自己的环境中运行这段代码,并尝试:

  1. 增加"最多 7 次"的尝试次数限制
  2. 游戏结束后,用 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 个练习和猜数字项目独立完成后再继续。

十一、参考资料

相关推荐
bestcxx1 小时前
多个维度对 Java、Python、C#、Go 这四种主流编程语言进行比较
java·python·c#
云深处@1 小时前
【项目一】高并发内存池
java·开发语言
阿里嘎多学长1 小时前
2026-05-04 GitHub 热点项目精选
开发语言·程序员·github·代码托管
山峰哥1 小时前
SQL性能提升20倍的秘密:这些优化技巧让DBA都惊叹
开发语言·数据库·sql·编辑器·深度优先·宽度优先
pengyu2 小时前
【Kotlin 协程修仙录 · 金丹境 · 初阶】 | 并发艺术:async/await 与并发组合的优雅之道
android·kotlin
2zcode2 小时前
基于MATLAB的家用场景下扫地机器人路径规划研究设计
开发语言·matlab·机器人
书源丶2 小时前
三十九、Java 枚举——固定常量的「安全卫士」
java·开发语言
计算机毕业编程指导师2 小时前
【大数据毕设推荐】Hadoop+Spark电影票房分析系统,Python+Django全栈实现 毕业设计 选题推荐 毕设选题 数据分析 机器学习 数据挖掘
大数据·hadoop·python·计算机·spark·毕业设计·电影票房
上弦月-编程2 小时前
高效编程利器:转移表技术解析
c语言·开发语言·数据结构·算法·排序算法