1. Kotlin语言基础:Kotlin发展史、与Java对比、变量与常量、基本数据类型、类型推断与空安全
各位同学,咱们正式开始这门课的第一章。说实话,每次讲Kotlin基础,我都会想起自己从Java转过来的那段日子。那时候心里直打鼓——学了这么多年Java,换个新语言值不值?后来我发现,这根本不是二选一的问题,而是多了一把更趁手的工具。
1.1 Kotlin发展史:从JetBrains的实验室到Google的官方语言
Kotlin的故事,得从2011年说起。那时候JetBrains(就是做IntelliJ IDEA那家公司)的工程师们,觉得Java虽然强大,但写起来太啰嗦了。他们想要一种更简洁、更安全、还能和Java无缝互操作的语言。于是,Kotlin项目在圣彼得堡悄悄启动了。
2016年,Kotlin 1.0正式发布。我记得当时在技术社区里,大家的态度是「又一个JVM语言?Scala都没搞明白呢」。但到了2017年Google I/O大会,事情彻底变了——Google宣布Kotlin成为Android官方开发语言。那天我的朋友圈直接刷屏了。
为什么会这样?说白了,Google需要一个比Java更现代、比Scala更轻量的选择。Kotlin恰好站在了这个位置上。到了2019年,Google更是宣布「Kotlin-first」,新API的示例代码优先用Kotlin写。嗯,这时候再犹豫就说不过去了。
我个人习惯把Kotlin的发展分成三个阶段:
- 探索期(2011-2016):JetBrains内部孵化,社区小范围试用
- 爆发期(2017-2019):Google官方支持,Android开发者大规模涌入
- 成熟期(2020至今):多平台支持(KMP),服务端、前端、iOS全面开花
现在Kotlin已经发展到2.0版本了。你想想看,一个语言从诞生到成为主流,只用了十年出头。这背后是JetBrains对开发者痛点的精准把握——他们自己就是做工具的,最懂程序员想要什么。
1.2 Kotlin与Java对比:不是替代,而是进化
很多新手会问:「学了Kotlin是不是就不用学Java了?」我的回答是:别这么想。Kotlin和Java的关系,更像是「进化」而非「替代」。它们共享JVM生态,可以互相调用,甚至可以在同一个项目中混用。
我给大家列个对比表,这样更直观:
| 对比维度 | Java | Kotlin |
|---|---|---|
| 空安全 | 需要手动判空 | 类型系统内置空安全 |
| 类型推断 | Java 10+才支持局部变量推断 | 从一开始就全面支持 |
| 函数式编程 | Lambda支持有限 | 一等公民,高阶函数、闭包 |
| 扩展函数 | 不支持 | 原生支持,非常实用 |
| 数据类 | 需要手写getter/setter/equals/hashCode | 一行data class搞定 |
| 协程 | 需要第三方库 | 语言级支持 |
我在项目中遇到过最典型的场景:一个Java写的旧模块,需要接入Kotlin的新功能。你猜怎么着?直接把Kotlin文件扔进项目,Java代码里直接调用,完全没问题。这种互操作性,是Kotlin最大的杀手锏。
核心观点:Kotlin不是要杀死Java,而是给Java开发者一个更好的选择。如果你维护的是纯Java老项目,没必要强行迁移;但如果是新项目,我建议你优先考虑Kotlin。
1.3 变量与常量:val和var的选择哲学
Kotlin里声明变量只有两个关键字:val和var。简单说:
val(value):只读变量,赋值后不可变(类似Java的final)var(variable):可变变量,可以重新赋值
看个例子:
// 常量:一旦赋值,不能修改
val name: String = "Kotlin"
// name = "Java" // 编译错误!
// 变量:可以重新赋值
var version: Int = 1
version = 2 // 没问题
我个人习惯是:能用val就不用var。为什么?因为不可变性是减少bug最有效的手段之一。你想想看,一个变量如果到处都能改,调试的时候你根本不知道它什么时候被谁改了。用val,相当于给变量上了一把锁。
我曾经在一个项目里接手过一段代码,里面全是var,而且变量名还特别随意(比如a、b、tmp)。调试一个并发bug花了整整两天,最后发现是某个var在另一个线程被意外修改了。从那以后,我写代码的第一原则就是:先声明val,除非你确定它必须变。
小技巧:在Android开发中,很多场景其实可以用val。比如RecyclerView的Adapter里的数据列表,很多人习惯用var,但其实用val配合copy()方法更安全。
1.4 基本数据类型:一切皆对象
Kotlin的基本数据类型和Java很像,但有一个关键区别:Kotlin里没有原始类型,一切皆对象。也就是说,Int、Long、Float这些,在Kotlin里都是类。
常用的基本数据类型:
- 数值类型:Byte、Short、Int、Long、Float、Double
- 字符类型:Char(注意,不是Java的char)
- 布尔类型:Boolean(true/false)
- 字符串类型:String
看个代码示例:
val intNum: Int = 42
val longNum: Long = 42L // L后缀表示Long
val floatNum: Float = 3.14f // f后缀表示Float
val doubleNum: Double = 3.14
val charVal: Char = 'A'
val boolVal: Boolean = true
val strVal: String = "Hello"
这里有个坑要注意:Kotlin里数字没有隐式转换。你不能直接把Int赋值给Long:
val a: Int = 10
// val b: Long = a // 编译错误!
val b: Long = a.toLong() // 必须显式转换
嗯,刚开始可能会觉得麻烦,但习惯了就会发现,这其实避免了Java里那种「int转long丢精度」的坑。
1.5 类型推断:让代码更简洁的秘密武器
Kotlin的类型推断,说白了就是:编译器能猜出你的类型,你就不用写了。比如:
val name = "Kotlin" // 编译器自动推断为String
var count = 10 // 编译器自动推断为Int
val price = 19.99 // 编译器自动推断为Double
是不是清爽多了?但要注意,类型推断不是万能的。有些场景你必须显式声明类型:
- 函数返回值类型(除非是Unit)
- 类的属性(成员变量)
- 接口或抽象类的实现
我个人习惯是:局部变量尽量用类型推断,公开API显式声明类型。这样既保持了代码简洁,又保证了可读性。
避坑指南:我曾经见过有人滥用类型推断,写出来的代码像天书。比如:
val result = someComplexFunction().let { it?.run { ... } }
这种代码,编译器能推断,但人眼根本看不懂。记住:类型推断是为了让代码更清晰,不是更模糊。
1.6 空安全:Kotlin最让我安心的特性
说到空安全,我得先吐槽一下Java的NullPointerException。我相信每个Java开发者都遇到过NPE,那种「明明判空了怎么还是空」的绝望感,懂的都懂。
Kotlin的空安全,核心就两句话:
- 类型默认不可为空:
String表示一定不为null - 可空类型用 ? 标记:
String?表示可能为null
看代码:
// 不可空类型
val name: String = "Kotlin"
// name = null // 编译错误!
// 可空类型
val nullableName: String? = null
nullableName = "Java" // 可以赋值非空
nullableName = null // 也可以赋值null
那么问题来了:如果拿到一个可空类型,怎么安全地使用它?Kotlin提供了几种操作符:
- 安全调用操作符 ?.:如果对象为null,直接返回null,不会调用方法
- Elvis操作符 ?::如果左边为null,使用右边的默认值
- 非空断言 !!:强制认为不为null(慎用!)
示例:
val str: String? = "Hello"
// 安全调用
val length = str?.length // 如果str为null,length也为null
// Elvis操作符
val lengthOrZero = str?.length ?: 0 // 如果str为null,返回0
// 非空断言(慎用!)
val lengthForce = str!!.length // 如果str为null,抛出NPE
我的建议:能用?.和?:解决的问题,绝对不要用!!。我在代码审查时看到!!,基本都会要求改成安全调用。除非你100%确定这个值不可能为null,比如从Bundle里取出的数据已经判过空了。
我曾经在一个支付模块里,因为用了!!导致线上崩溃。原因是某个接口返回的数据结构变了,某个字段变成了null,但代码里用了!!强制解包。那次事故之后,我定了个规矩:项目中禁止使用!!,除非有充分的注释说明。
小结
这一章我们聊了Kotlin的来龙去脉,对比了它和Java的差异,也把变量、常量、数据类型、类型推断和空安全这些基础概念过了一遍。说实话,这些内容看起来简单,但它们是Kotlin一切高级特性的基石。
下一章,我们会深入函数和Lambda表达式。到时候你会发现,Kotlin的函数式编程能力,才是它真正的杀手锏。咱们下节课见。