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里声明变量只有两个关键字:valvar。简单说:

  • val(value):只读变量,赋值后不可变(类似Java的final)
  • var(variable):可变变量,可以重新赋值

看个例子:

// 常量:一旦赋值,不能修改
val name: String = "Kotlin"
// name = "Java"  // 编译错误!

// 变量:可以重新赋值
var version: Int = 1
version = 2  // 没问题

我个人习惯是:能用val就不用var。为什么?因为不可变性是减少bug最有效的手段之一。你想想看,一个变量如果到处都能改,调试的时候你根本不知道它什么时候被谁改了。用val,相当于给变量上了一把锁。

我曾经在一个项目里接手过一段代码,里面全是var,而且变量名还特别随意(比如abtmp)。调试一个并发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提供了几种操作符:

  1. 安全调用操作符 ?.:如果对象为null,直接返回null,不会调用方法
  2. Elvis操作符 ?::如果左边为null,使用右边的默认值
  3. 非空断言 !!:强制认为不为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的函数式编程能力,才是它真正的杀手锏。咱们下节课见。