Kotlin 教程

Kotlin 教程

Kotlin 是由 JetBrains 开发的现代化静态类型编程语言,2017 年被 Google 指定为 Android 官方开发语言,也可用于后端、Web、桌面与多平台开发。它运行在 JVM 之上,与 Java 100% 互操作,同时吸收了函数式编程与空安全等现代语言特性。

为什么选择 Kotlin?

  • 简洁:代码量比 Java 平均减少约 40%,没有样板代码(如 getter/setter、构造函数模板)
  • 安全:内置空安全机制,编译期即消除大量空指针异常
  • 互操作:可直接调用现有 Java 库,与 Java 代码无缝混编
  • 多平台:一套代码可编译为 JVM、JavaScript 与原生二进制

学习路线

  1. 环境搭建(IntelliJ IDEA / Eclipse / 命令行)
  2. 基础语法与数据类型
  3. 条件与循环控制
  4. 面向对象:类、继承、接口、扩展、数据类
  5. 高级特性:泛型、枚举、对象表达式、委托

第一个程序

fun main() {
    println("Hello, Kotlin!")
}

无需分号,无需 main 类,直接函数即入口,这是 Kotlin 简洁性的第一印象。

接下来我们将从环境搭建开始,一步步掌握这门语言。

Kotlin IntelliJ IDEA 环境搭建

Kotlin IntelliJ IDEA 环境搭建

IntelliJ IDEA 是 JetBrains 官方 IDE,对 Kotlin 支持最完善,是 Kotlin 开发的首选工具。

1. 安装 JDK

Kotlin 运行在 JVM 上,需要先安装 JDK(建议 JDK 8 或更高版本):

# macOS
brew install openjdk
# Ubuntu
sudo apt install openjdk-11-jdk
# 验证
java -version

2. 下载安装 IntelliJ IDEA

  • 访问 JetBrains 官网下载 Community(免费)或 Ultimate(付费)版本
  • 安装完成后打开,选择 New Project

3. 创建 Kotlin 项目

  1. File → New → Project
  2. 选择 Kotlin 分类,语言选 Kotlin,构建系统选 Gradle 或 IntelliJ
  3. 选择 JDK 版本,点击 Finish

4. 编写并运行

fun main() {
    println("Hello from IntelliJ!")
}

右键 main 函数 → Run,即可在控制台看到输出。IDEA 内置的 Kotlin 插件已自动启用,无需额外配置。

常用快捷键

  • Shift+F10:运行当前文件
  • Alt+Enter:快速修复/补全
  • Cmd/Ctrl+N:查找类

Kotlin Eclipse 环境搭建

Kotlin Eclipse 环境搭建

如果习惯使用 Eclipse,也可以通过安装 Kotlin 插件进行开发。

1. 安装插件

  1. 打开 Eclipse → Help → Eclipse Marketplace
  2. 搜索 Kotlin,找到 JetBrains 提供的 Kotlin Plugin
  3. 点击 Install,重启 Eclipse

2. 创建 Kotlin 项目

  1. File → New → Project
  2. 选择 Kotlin Project
  3. 右键 src 目录 → New → Kotlin File

3. 配置 Kotlin 编译器

Eclipse 插件会自动管理 Kotlin 编译器与运行时,右键项目 → Properties → Kotlin Compiler,可查看/修改编译选项:

jvmTarget = 1.8
languageVersion = 1.9
apiVersion = 1.9

4. 运行

fun main() {
    println("Kotlin on Eclipse!")
}

右键文件 → Run As → Kotlin Application,即可看到输出。

提示:Eclipse 对 Kotlin 的支持不如 IntelliJ 完善,建议大型项目使用 IntelliJ IDEA。

Kotlin 使用命令行编译

Kotlin 使用命令行编译

不依赖 IDE,仅通过命令行即可编译运行 Kotlin 程序,适合脚本化与 CI 环境。

1. 安装 Kotlin 命令行编译器

# macOS (Homebrew)
brew install kotlin
# SDKMAN
curl -s "https://get.sdkman.io" | bash
sdk install kotlin
# 验证
kotlinc -version

2. 编写源文件

创建 hello.kt:

fun main() {
    println("Hello, Kotlin CLI!")
}

3. 编译运行

# 编译为 JVM 字节码
kotlinc hello.kt -include-runtime -d hello.jar
# 运行
java -jar hello.jar
# 或者直接运行脚本
kotlinc -script hello.kt

4. 编译多个文件

kotlinc file1.kt file2.kt -include-runtime -d app.jar
java -jar app.jar

5. 与 Maven/Gradle 配合

实际项目中建议用构建工具管理依赖,在 build.gradle.kts 中:

plugins {
    kotlin("jvm") version "1.9.0"
}

命令行方式适合快速验证与学习,生产项目推荐 Gradle。

Kotlin Android 环境搭建

Kotlin Android 环境搭建

Kotlin 是 Android 官方推荐语言,Android Studio 内置完整支持。

1. 安装 Android Studio

  1. 从官网下载 Android Studio
  2. 安装时勾选 Android SDK 组件
  3. 创建第一个项目时,语言选择 Kotlin

2. 项目结构

app/
├── src/main/java/com/example/app/
│   └── MainActivity.kt
└── build.gradle.kts

3. 编写 Activity

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<TextView>(R.id.tvHello).text = "Hello Kotlin!"
    }
}

4. 布局文件

<TextView
    android:id="@+id/tvHello"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

5. 运行调试

  • 连接设备或启动模拟器
  • 点击 Run 按钮(绿色三角)
  • 使用 Logcat 查看日志、断点调试

6. 常用库

  • Jetpack Compose:现代声明式 UI 框架
  • Coroutines:协程处理异步任务
  • Retrofit:网络请求

Kotlin 基础语法

Kotlin 基础语法

1. 包声明与导入

package com.example.demo

import java.util.Date

fun main() {
    println(Date())
}

2. 变量声明

Kotlin 用 val(不可变)与 var(可变)声明变量,类型可自动推断:

val name = "Kotlin"        // 字符串,不可重新赋值
var age = 10               // 整数,可变
val price: Double = 19.9   // 显式指定类型
age = 11                   // 允许

3. 函数定义

// 传统写法
fun sum(a: Int, b: Int): Int {
    return a + b
}

// 表达式函数体
fun sum2(a: Int, b: Int) = a + b

// 默认参数
fun greet(name: String = "World") = "Hello, $name"

4. 字符串模板

val name = "Kotlin"
println("Hello, $name!")       // Hello, Kotlin!
println("长度: ${name.length}") // 长度: 6

5. 注释

// 单行注释
/* 多行
   注释 */
/** KDoc 文档注释 */

6. 空安全

var s: String? = null        // 可空类型
println(s?.length)           // 安全调用,输出 null
println(s?.length ?: 0)      // Elvis 运算符,输出 0
// s!!.length               // 强制非空,可能抛异常

Kotlin 基本数据类型

Kotlin 基本数据类型

1. 数值类型

val b: Byte = 127
val s: Short = 32767
val i: Int = 2147483647
val l: Long = 9223372036854775807L
val f: Float = 3.14F
val d: Double = 3.1415926
val hex = 0x0F     // 十六进制
val bin = 0b1010   // 二进制

2. 布尔与字符

val flag: Boolean = true
val c: Char = 'A'
val esc = '\n'      // 转义字符
val unicode = '\uFF00'

3. 类型转换

Kotlin 不允许隐式转换,必须显式调用:

val i = 100
val l = i.toLong()
val d = i.toDouble()
val s = i.toString()
val back = s.toInt()

4. 位运算

val a = 0b1100
val b = 0b1010
println(a and b)   // 8  与
println(a or b)    // 14 或
println(a xor b)   // 6  异或
println(a shl 1)   // 24 左移
println(a shr 1)   // 6  右移

5. 字符串

val s = "Hello"
println(s[0])           // H
println(s.length)       // 5
println(s.uppercase())  // HELLO
// 原始字符串
val raw = """多行
字符串内容"""
println(raw)

6. 数组

val arr = intArrayOf(1, 2, 3)
val list = arrayOf("a", "b", "c")
println(arr[0])
println(arr.size)

Kotlin 条件控制

Kotlin 条件控制

1. if 表达式

Kotlin 的 if 是表达式,可直接返回值:

val a = 10
val b = 20

// 传统用法
var max = a
if (a < b) max = b

// 表达式用法
val max2 = if (a > b) a else b

// 多分支
val grade = if (score >= 90) "A"
            else if (score >= 80) "B"
            else if (score >= 70) "C"
            else "D"

2. when 表达式

when 替代 Java 的 switch,更强大:

fun describe(x: Any): String = when (x) {
    1 -> "One"
    "Hello" -> "Greeting"
    is Long -> "Long number"
    !is String -> "Not a string"
    else -> "Unknown"
}

// when 分支可以用区间
fun score(s: Int) = when (s) {
    in 90..100 -> "优秀"
    in 80..89 -> "良好"
    in 60..79 -> "及格"
    else -> "不及格"
}

// when 不带参数
fun isWeekend(day: String) = when {
    day == "周六" || day == "周日" -> true
    else -> false
}

3. 区间

val r1 = 1..10        // 1 到 10(含)
val r2 = 1 until 10   // 1 到 9(不含10)
val r3 = 10 downTo 1  // 10 到 1 递减
val r4 = 1..10 step 2 // 1,3,5,7,9

Kotlin 循环控制

Kotlin 循环控制

1. for 循环

// 遍历区间
for (i in 1..5) {
    println(i)
}

// 遍历数组
val arr = arrayOf("a", "b", "c")
for (item in arr) {
    println(item)
}

// 带索引
for ((index, value) in arr.withIndex()) {
    println("$index -> $value")
}

// 指定步长与倒序
for (i in 10 downTo 1 step 2) {
    println(i)
}

2. while 循环

var i = 0
while (i < 5) {
    println("i = $i")
    i++
}

var j = 0
do {
    println("至少执行一次: $j")
    j++
} while (j < 3)

3. break 与 continue

for (i in 1..10) {
    if (i == 3) continue   // 跳过 3
    if (i == 8) break      // 到 8 退出
    println(i)
}

// 标签跳出外层循环
outer@ for (i in 1..3) {
    for (j in 1..3) {
        if (j == 2) break@outer
        println("$i-$j")
    }
}

4. 遍历集合

val map = mapOf("a" to 1, "b" to 2)
for ((k, v) in map) {
    println("$k = $v")
}

Kotlin 类和对象

Kotlin 类和对象

1. 类定义

class Person {
    var name: String = ""
    var age: Int = 0

    fun speak() {
        println("$name 在说话")
    }
}

val p = Person()
p.name = "张三"
p.age = 25
p.speak()

2. 构造函数

// 主构造函数
class User(val name: String, var age: Int) {
    // 初始化块
    init {
        println("User 创建: $name")
    }

    // 次构造函数
    constructor(name: String) : this(name, 0)
}

val u1 = User("李四", 30)
val u2 = User("王五")

3. 属性与 getter/setter

class Circle(radius: Double) {
    var radius = radius
        get() = field
        set(value) {
            if (value > 0) field = value
        }
    val area: Double
        get() = 3.14159 * radius * radius
}

4. 可见性修饰符

  • public(默认):所有地方可见
  • private:类内可见
  • protected:类及子类可见
  • internal:模块内可见

5. 伴生对象

class MathUtil {
    companion object {
        const val PI = 3.14159
        fun square(x: Double) = x * x
    }
}

println(MathUtil.PI)
println(MathUtil.square(4.0))

Kotlin 继承

Kotlin 继承

Kotlin 中所有类默认是 final 的,必须用 open 关键字标记才能被继承。

1. 定义可继承的类

open class Animal(val name: String) {
    // open 方法才能被重写
    open fun sound() {
        println("$name 发出声音")
    }
}

2. 继承与重写

class Dog(name: String) : Animal(name) {
    override fun sound() {
        println("$name 汪汪叫")
    }
}

class Cat(name: String) : Animal(name) {
    override fun sound() {
        super.sound()  // 调用父类实现
        println("$name 喵喵叫")
    }
}

val d = Dog("旺财")
d.sound()  // 旺财 汪汪叫

3. 抽象类

abstract class Shape {
    abstract fun area(): Double
    fun describe() = "面积是 ${area()}"
}

class Square(val side: Double) : Shape() {
    override fun area() = side * side
}

4. 多态

val animals: List<Animal> = listOf(Dog("A"), Cat("B"))
for (a in animals) {
    a.sound()  // 运行时动态分派
}

5. 属性重写

open class Base {
    open val value: Int = 10
}

class Derived : Base() {
    override val value: Int = 20
}

Kotlin 接口

Kotlin 接口

Kotlin 接口可以包含抽象方法、带默认实现的方法和属性声明。

1. 定义接口

interface Flyable {
    // 抽象方法
    fun fly()

    // 带默认实现
    fun land() {
        println("正在降落...")
    }

    // 属性(接口中只能声明,不能初始化)
    val maxSpeed: Int
}

2. 实现接口

class Bird : Flyable {
    override val maxSpeed = 100

    override fun fly() {
        println("小鸟在飞,速度 $maxSpeed")
    }
}

val b = Bird()
b.fly()
b.land()  // 使用默认实现

3. 多接口实现

interface A {
    fun foo() { println("A.foo") }
}
interface B {
    fun foo() { println("B.foo") }
}

class C : A, B {
    // 冲突时必须手动指定
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }
}

4. 接口继承

interface Movable {
    fun move() { println("移动中") }
}

interface Swimmable : Movable {
    fun swim() { println("游泳中") }
}

class Fish : Swimmable {
    // 只需实现未默认的方法
}

5. 函数式接口(SAM)

fun interface ClickListener {
    fun onClick(view: String)
}

val listener = ClickListener { view ->
    println("点击了 $view")
}
listener.onClick("button")

Kotlin 扩展

Kotlin 扩展

扩展函数/扩展属性允许在不修改原有类的情况下为其添加新功能,极大增强代码复用。

1. 扩展函数

// 为 String 添加扩展函数
fun String.reverse(): String = this.reversed()

// 为 List 添加扩展
fun <T> List<T>.secondOrNull(): T? = if (size > 1) this[1] else null

println("kotlin".reverse())   // niltoK
println(listOf(1,2,3).secondOrNull())  // 2

2. 扩展属性

val String.isEmail: Boolean
    get() = this.contains("@") && this.contains(".")

println("test@example.com".isEmail)  // true

3. 伴生对象扩展

class MyClass {
    companion object { }
}

fun MyClass.Companion.create() = MyClass()
val m = MyClass.create()

4. 扩展与成员冲突

当成员函数与扩展函数同名时,成员函数优先:

class C {
    fun foo() = "成员"
}
fun C.foo() = "扩展"
C().foo()  // 输出 "成员"

5. 常用扩展库

  • apply/also/let/run/with:作用域函数,简化对象操作
  • takeIf/takeUnless:条件返回
  • to:创建 Pair
val user = User().apply {
    name = "张三"
    age = 20
}

Kotlin 数据类与密封类

Kotlin 数据类与密封类

1. 数据类(data class)

数据类自动生成 equals、hashCode、toString、copy 和 componentN 方法:

data class User(val id: Int, val name: String, val email: String = "")

val u1 = User(1, "张三")
val u2 = User(1, "张三")
println(u1 == u2)        // true(结构相等)
println(u1.toString())   // User(id=1, name=张三, email=)

// copy 复制并修改
val u3 = u1.copy(name = "李四")

// 解构声明
val (id, name, email) = u1
println("$id $name $email")

2. 数据类要求

  • 主构造函数至少有一个参数
  • 所有主构造参数用 val/var 标记
  • 不能是抽象、开放、密封或内部类

3. 密封类(sealed class)

密封类限制继承层级,所有子类必须在同一文件或包中,配合 when 实现穷尽分支:

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val code: Int, val msg: String) : Result()
    object Loading : Result()
}

fun handle(r: Result) = when (r) {
    is Result.Success -> "成功: ${r.data}"
    is Result.Error -> "失败(${r.code}): ${r.msg}"
    Result.Loading -> "加载中..."
}

4. 密封接口

sealed interface Shape {
    data class Circle(val r: Double) : Shape
    data class Rect(val w: Double, val h: Double) : Shape
}

Kotlin 泛型

Kotlin 泛型

1. 泛型函数

fun <T> identity(value: T): T = value

fun <T> List<T>.firstOr(default: T): T = if (isEmpty()) default else this[0]

println(identity("hello"))          // hello
println(listOf(1,2).firstOr(0))     // 1
println(emptyList<Int>().firstOr(0)) // 0

2. 泛型类

class Box<T>(val content: T) {
    fun get(): T = content
}

val intBox = Box(123)
val strBox = Box<String>("abc")

3. 类型上界

// T 必须是 Comparable 的子类型
fun <T : Comparable<T>> maxOf2(a: T, b: T): T =
    if (a > b) a else b

println(maxOf2(10, 20))   // 20
println(maxOf2("a", "b")) // b

4. 型变:协变(out)与逆变(in)

// out:只能读取(生产者)
interface Source<out T> {
    fun next(): T
}

// in:只能写入(消费者)
interface Sink<in T> {
    fun accept(value: T)
}

5. 星投影

fun printList(list: List<*>) {
    println(list.size)
}

printList(listOf(1, "a", true))

6. 泛型约束

fun <T> T.safeCastTo(clazz: Class<T>): T? = clazz.cast(this)

Kotlin 枚举类

Kotlin 枚举类

1. 基本枚举

enum class Direction {
    NORTH, SOUTH, EAST, WEST
}

val d = Direction.NORTH
println(d.name)      // NORTH
println(d.ordinal)   // 0

2. 带属性与构造参数

enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF);

    fun hex(): String = "#%06X".format(rgb)
}

println(Color.RED.hex())  // #FF0000

3. 枚举方法

// 遍历
for (c in Color.values()) {
    println("${c.name}: ${c.hex()}")
}

// 按名称获取
val c = Color.valueOf("GREEN")

// 按位置获取
val second = Color.entries[1]

4. 枚举与 when 组合

enum class HttpStatus(val code: Int) {
    OK(200), NOT_FOUND(404), ERROR(500)
}

fun describe(s: HttpStatus) = when (s) {
    HttpStatus.OK -> "成功"
    HttpStatus.NOT_FOUND -> "未找到"
    HttpStatus.ERROR -> "服务器错误"
}

println(describe(HttpStatus.OK))

5. 枚举实现接口

interface Describable {
    fun describe(): String
}

enum class Planet : Describable {
    EARTH {
        override fun describe() = "地球,人类家园"
    },
    MARS {
        override fun describe() = "火星,红色星球"
    }
}

Kotlin 对象表达式/声明

Kotlin 对象表达式/声明

1. 对象表达式(匿名对象)

用于创建临时对象,常用于实现接口或继承类:

val listener = object : ClickListener {
    override fun onClick() {
        println("按钮被点击")
    }
}

// 匿名对象作为参数
fun setClick(handler: () -> Unit) { handler() }
setClick(object : () -> Unit {
    override fun invoke() { println("执行") }
})

2. 对象声明(单例)

// object 关键字创建单例
object Config {
    val appName = "MyApp"
    var version = "1.0"

    fun show() {
        println("$appName v$version")
    }
}

Config.show()  // 全局唯一实例
Config.version = "1.1"

3. 伴生对象(companion object)

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
        val TAG = "MyClass"
    }
}

// 两种调用方式
val a = MyClass.create()
val b = MyClass.Factory.create()
println(MyClass.TAG)

4. 对象表达式 vs 声明区别

特性对象表达式对象声明
初始化时机每次使用时首次访问时(懒加载)
用途临时对象单例
可赋值给变量是否(全局单例)

5. 使用场景

  • 比较器: val cmp = object : Comparator<Int> {...}
  • 数据模型伴生工厂方法
  • 全局配置、工具函数容器

kotlin 委托

Kotlin 委托

1. 类委托

通过 by 关键字将接口实现委托给另一个对象,实现组合复用:

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { println("BaseImpl: $x") }
}

// 委托给 b,所有方法自动转发
class Derived(b: Base) : Base by b

val base = BaseImpl(10)
val d = Derived(base)
d.print()  // BaseImpl: 10

2. 委托属性

// lazy 委托:第一次访问时初始化
val lazyValue: String by lazy {
    println("计算中...")
    "计算结果"
}

println(lazyValue)  // 计算中... 计算结果
println(lazyValue)  // 直接返回缓存值

// observable 委托:值变化时回调
var observed: String by Delegates.observable("初始") {
    prop, old, new -> println("$old -> $new")
}
observed = "新值"  // 初始 -> 新值

// vetoable 委托:可拦截赋值
var age: Int by Delegates.vetoable(18) {
    _, _, new -> new in 0..150
}

3. 自定义委托

class LoggingDelegate<T>(private var value: T) {
    operator fun getValue(thisRef: Any?, prop: kotlin.reflect.KProperty<*>): T {
        println("读取 ${prop.name} = $value")
        return value
    }

    operator fun setValue(thisRef: Any?, prop: kotlin.reflect.KProperty<*>, newValue: T) {
        println("写入 ${prop.name} = $newValue")
        value = newValue
    }
}

var name by LoggingDelegate("默认")
name = "张三"   // 写入 name = 张三
println(name)  // 读取 name = 张三

4. 委托场景

  • ViewModel 属性懒加载
  • SharedPreferences 封装
  • 属性变更监听与校验
第 1 / 18 节