【安卓开发】Kotlin入门教程

一、Kotlin 基础入门

1.1 Kotlin 简介

Kotlin 是一种由 JetBrains 开发的静态类型编程语言,运行在 Java 虚拟机上,也可以编译为 JavaScript 或原生代码。它于 2017 年被 Google 宣布为 Android 官方开发语言。

主要特点:

  • 简洁:相比 Java 减少约 40% 的样板代码

  • 安全:内置空安全机制

  • 互操作:100% 兼容 Java

  • 工具友好:由 JetBrains 开发,IDE 支持完善

1.2 开发环境搭建:Android Studio 配置

  1. Android Studio 3.0+ 已内置 Kotlin 支持

  2. 可通过插件管理器确认 Kotlin 插件状态

  3. 转换现有 Java 文件:Code > Convert Java File to Kotlin File

1.3 基本语法结构

1.3.1 Hello World 程序
fun main() {
    println("Hello, World!")
}

与 Java 对比:

  • 没有类声明也能运行

  • 函数使用 fun 关键字

  • 分号可选

  • 打印使用 println 而非 System.out.println

1.4 变量与常量

1.4.1 变量声明
var mutableVar: String = "可变变量"
val immutableVal: Int = 42 // 类似 Java 的 final

类型推断:

var inferredString = "类型推断为 String"
val inferredInt = 123 // 推断为 Int
1.4.2 基本数据类型

Kotlin 中所有数据类型都是对象:

类型位宽示例
Byte8123
Short1612345
Int321234567890
Long64123L
Float32123.45f
Double64123.45
Char16'A'
Boolean-true/false

类型转换:

val intValue = 42
val longValue = intValue.toLong() // 显式转换
1.4.3 字符串模板
val name = "Alice"
println("Hello, $name!") // 简单变量
println("Name length: ${name.length}") // 表达式

多行字符串:

val text = """
    |第一行
    |第二行
    |第三行
""".trimMargin()

第二章:Kotlin 函数编程

2.1 函数定义

2.1.1 基本函数
fun sum(a: Int, b: Int): Int {
    return a + b
}
2.1.2 表达式函数体
fun sum(a: Int, b: Int) = a + b
2.1.3 默认参数
fun greet(name: String = "World") {
    println("Hello, $name!")
}

greet() // Hello, World!
greet("Alice") // Hello, Alice!
2.1.4 命名参数
fun createUser(
    id: Int,
    name: String,
    email: String = "",
    age: Int = 0
) { /*...*/ }

// 调用
createUser(
    id = 1,
    name = "Alice",
    age = 25
)

2.2 高阶函数

2.2.1 函数作为参数
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

val result = calculate(10, 5) { x, y -> x + y }
2.2.2 函数作为返回值
fun getOperation(type: String): (Int, Int) -> Int {
    return when(type) {
        "add" -> { a, b -> a + b }
        "multiply" -> { a, b -> a * b }
        else -> { _, _ -> 0 }
    }
}

2.3 Lambda 表达式

基本语法:

val sum = { x: Int, y: Int -> x + y }
println(sum(1, 2)) // 3

带接收者的 Lambda:

val stringPlus: String.(String) -> String = { this + it }

println("Hello".stringPlus("World")) // HelloWorld

2.4 内联函数

inline fun measureTime(block: () -> Unit) {
    val start = System.currentTimeMillis()
    block()
    println("执行时间: ${System.currentTimeMillis() - start}ms")
}

measureTime {
    // 要测量的代码
}

三、Kotlin 面向对象编程

3.1 类与对象:Kotlin的核心抽象单元

Kotlin的类系统在保持与Java互操作性的同时,通过精简的语法显著提升了开发效率。类的声明可以包含构造函数、属性初始化、成员函数等多个部分,但语法比Java更加紧凑。

3.1.1 主构造函数与初始化块

主构造函数是类头的一部分,它跟在类名后面,可以包含参数声明。这些参数不仅用于构造实例,还可以直接声明为类属性:

class Person(
    val name: String,       // 只读属性
    var age: Int,           // 可变属性
    gender: String          // 构造函数参数(非属性)
) {
    init {
        require(age > 0) { "年龄必须为正数" }
        println("创建Person实例: $name")
    }
    
    val genderUpper = gender.uppercase()  // 属性初始化
}

关键点

  • init 块在对象创建时执行,可以有多个(按声明顺序执行)

  • 主构造函数参数加 val/var 才会成为属性

  • 属性可以在类体内直接初始化

3.1.2 次构造函数与默认值

当需要多种构造方式时,可以定义次构造函数。但在Kotlin中,更推荐使用默认参数替代多个构造函数:

class User {
    constructor(email: String) {
        // 从email构造
    }
    
    constructor(facebookId: Long) {
        // 从社交账号构造
    }
}

// 更Kotlin化的方式(使用默认参数)
class BetterUser(
    val email: String? = null,
    val facebookId: Long? = null
) {
    init {
        require(email != null || facebookId != null) {
            "至少需要一种登录方式"
        }
    }
}

3.2 继承体系:更安全的类扩展机制

Kotlin的继承系统通过明确的修饰符设计,强制开发者更谨慎地处理继承关系,避免了Java中常见的继承滥用问题。

3.2.1 类继承的基本规则
open class Animal(val name: String) {  // 必须标记open才能被继承
    open val sound = "..."            // 必须标记open才能被重写
    
    open fun makeSound() {
        println(sound)
    }
    
    fun eat() { /* 默认final */ }
}

class Cat(name: String) : Animal(name) {
    override val sound = "Meow"      // 属性重写
    
    final override fun makeSound() {  // 标记final禁止进一步重写
        super.makeSound()
        println("追加猫特有的行为")
    }
}

重要特性

  • 默认所有类都是final(与Java相反)

  • 必须显式使用 open 允许继承

  • override 关键字强制要求显式标注

  • 支持属性重写(而不仅是方法)

3.2.2 初始化顺序陷阱

Kotlin的类初始化顺序与Java不同,特别是在涉及属性重写时:

open class Base(val name: String) {
    init {
        println("初始化Base")
    }
    
    open val size: Int = name.length.also {
        println("初始化Base.size")
    }
}

class Derived(
    name: String,
    val lastName: String
) : Base(name.capitalize()) {
    init {
        println("初始化Derived")
    }
    
    override val size: Int = (super.size + lastName.length).also {
        println("初始化Derived.size")
    }
}

// 使用
Derived("hello", "world")

输出顺序

  1. Base的主构造函数参数求值(name.capitalize())

  2. Base的init块

  3. Base的属性初始化

  4. Derived的主构造函数参数初始化

  5. Derived的init块

  6. Derived的重写属性初始化

3.3 接口进化:带有默认实现的契约

Kotlin接口可以包含抽象属性、抽象方法以及带有默认实现的方法,比Java 8的接口更灵活:

interface Clickable {
    val clickable: Boolean    // 抽象属性
    
    fun click()              // 抽象方法
    
    fun showOff() = println("我是可点击的!")  // 默认实现
}

interface Focusable {
    fun showOff() = println("我是可聚焦的!")
}

class Button : Clickable, Focusable {
    override val clickable: Boolean = true
    
    override fun click() = println("按钮被点击")
    
    // 必须解决接口冲突
    override fun showOff() {
        super<Clickable>.showOff()
        super<Focusable>.showOff()
    }
}

接口特性

  • 支持属性声明(但不能保存状态)

  • 默认方法冲突必须显式解决

  • 可以实现多个接口

  • 与Java 8接口互操作

3.4 数据类:自动生成样板代码的利器

数据类(data class)是Kotlin中用于纯粹保存数据的特殊类,编译器会自动生成以下方法:

  • equals()/hashCode()

  • toString()

  • copy()

  • 解构声明(componentN()函数)

3.4.1 数据类的限制与技巧
data class Person(
    val name: String,
    val age: Int
) {
    var address: String = ""  // 不会参与equals/hashCode
    
    // 自定义copy行为
    fun copyWithPrefix(prefix: String) = copy(name = "$prefix$name")
}

// 使用示例
val person = Person("Alice", 25)
val (name, age) = person  // 解构声明
val olderAlice = person.copy(age = 30)

重要限制

  • 主构造函数必须至少有一个参数

  • 所有主构造参数必须标记为 val 或 var

  • 不能是 abstractopensealed 或 inner

3.4.2 深度复制与嵌套数据类

对于包含可变引用或嵌套集合的数据类,需要注意浅复制问题:

data class Company(val name: String, val employees: MutableList<Employee>)

// 安全复制方式
val newCompany = company.copy(
    employees = company.employees.toMutableList()
)

3.5 密封类:受限的类层次结构

密封类(sealed class)是枚举和抽象类的结合体,它限制了子类的可能类型,是实现代数数据类型(ADT)的理想选择。

3.5.1 密封类的典型应用
sealed class Result<out T> {
    data class Success<T>(val data: T) : Result<T>()
    data class Error(val exception: Throwable) : Result<Nothing>()
    object Loading : Result<Nothing>()
}

fun handleResult(result: Result<String>) = when(result) {
    is Result.Success -> println(result.data)
    is Result.Error -> println(result.exception)
    Result.Loading -> println("加载中...")
    // 不需要else分支,所有情况已覆盖
}

优势

  • 编译时检查穷尽所有可能类型

  • 保持多态特性(不同于枚举)

  • 每个子类可以有多个实例(除非定义为object)

  • 完美配合when表达式使用

3.5.2 密封类与枚举的选择
特性密封类枚举类
实例数量子类决定固定数量
状态携带可以携带复杂数据通常无状态或简单状态
穷尽检查支持支持
多态性保持丢失
性能稍低更高

适用场景

  • 需要携带不同数据的相关类型 → 密封类

  • 固定数量的简单常量 → 枚举

  • 需要模式匹配的场景 → 密封类

3.6 对象声明与伴生对象:Kotlin的单例模式

Kotlin使用 object 关键字实现单例模式,比Java的实现更简洁安全。

3.6.1 对象声明的多种用途
// 单例对象
object DatabaseManager {
    init {
        println("数据库连接初始化")
    }
    
    fun query(sql: String) { /*...*/ }
}

// 伴生对象(类内部的静态成员)
class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}

// 对象表达式(匿名对象)
val listener = object : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) { /*...*/ }
}

关键点

  • 对象声明是延迟初始化的(首次访问时初始化)

  • 伴生对象可以命名也可以匿名

  • 伴生对象可以继承接口

  • JVM上伴生对象成员会生成静态字段(使用@JvmStatic注解)

3.6.2 伴生对象的进阶用法
interface JSONFactory<T> {
    fun fromJSON(json: String): T
}

class Person(val name: String) {
    companion object : JSONFactory<Person> {
        override fun fromJSON(json: String): Person {
            // 解析JSON...
            return Person(/*...*/)
        }
    }
}

// 使用
val person = Person.fromJSON(jsonString)

四、Kotlin 高级特性

4.1 扩展函数与属性

扩展(Extensions)是Kotlin最强大的特性之一,它允许开发者为现有类添加新功能而无需继承或使用设计模式如装饰器。这种能力特别适合以下场景:

  • 当你想为第三方库或SDK中的类添加功能时

  • 需要保持代码整洁避免工具类泛滥时

  • 希望创建领域特定语言(DSL)时

4.1.1 扩展函数

扩展函数实际上是静态方法的语法糖。编译后,扩展函数会被转换为一个静态方法,接收者对象作为第一个参数

fun String.addEnthusiasm(amount: Int = 1): String {
    return this + "!".repeat(amount)
}

println("Hello".addEnthusiasm(3)) // Hello!!!

重要注意事项:

  • 扩展函数是静态解析的,不支持运行时多态

  • 如果扩展函数与成员函数签名相同,成员函数优先

  • 扩展可以定义在顶层,也可以定义在类内部(作用域受限)

4.1.2 扩展属性
val String.numberOfVowels: Int
    get() = count { it.toLowerCase() in setOf('a', 'e', 'i', 'o', 'u') }

println("Kotlin".numberOfVowels) // 2

4.2 运算符重载

Kotlin允许通过固定名称的函数重载数学运算符和比较操作,这使得自定义类型可以像基本类型一样参与运算,大幅提升代码可读性。

data class Point(val x: Int, val y: Int) {
    operator fun plus(other: Point): Point {
        return Point(x + other.x, y + other.y)
    }
}

val p1 = Point(1, 2)
val p2 = Point(3, 4)
println(p1 + p2) // Point(x=4, y=6)

4.3 委托

委托(Delegation)是Kotlin实现组合优于继承原则的核心机制,通过by关键字将接口实现委托给其他对象。

4.3.1 类委托的典型应用场景
  1. 装饰器模式:扩展功能而不修改原类

  2. 接口隔离:将大接口的实现拆分到不同对象

  3. 跨平台开发:将平台相关实现委托给具体平台模块

4.3.2类委托
interface Database {
    fun save(data: String)
}

class RealDatabase : Database {
    override fun save(data: String) { /*...*/ }
}

class DatabaseProxy(db: Database) : Database by db
4.3.3 属性委托
import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("<no name>") {
        prop, old, new ->
        println("$old -> $new")
    }
}

val user = User()
user.name = "Alice" // 输出: <no name> -> Alice
user.name = "Bob"   // 输出: Alice -> Bob

4.4 泛型

Kotlin的泛型系统在Java基础上进行了重要改进,解决了类型擦除带来的诸多限制。

4.4.1 型变注解深度解析
注解位置作用Java对应
out类型参数协变-只作为返回类型? extends
in类型参数逆变-只作为参数类型? super
reified内联函数保留类型信息
4.4.2 使用
class Box<T>(t: T) {
    var value = t
}

// 使用
val intBox = Box<Int>(1)
val stringBox = Box("String") // 类型推断

五、Kotlin 协程

5.1 协程基础

5.1.1 基本概念

协程(Coroutine)本质上是可挂起的计算实例,具有以下核心特点:

  1. 挂起不阻塞:挂起函数会释放底层线程供其他协程使用

  2. 结构化并发:协程之间存在明确的父子关系

  3. 调度灵活:可在不同线程间自由切换

  4. 资源高效:单个线程可运行数千个协程

5.1.2 协程与线程对比
特性线程协程
创建开销1MB+ 内存几十字节
切换成本微秒级纳秒级
并发数量数百到数千数百万
阻塞影响阻塞整个线程仅挂起当前协程
通信机制共享内存+锁Channel/Flow
5.1.3 基本使用
import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
}

5.2 协程构建器

// launch: 启动一个不返回结果的协程
val job = launch { /*...*/ }

// async: 启动一个返回 Deferred 结果的协程
val deferred = async { 
    delay(1000L)
    "Result" 
}
println(deferred.await())

// runBlocking: 阻塞当前线程直到协程完成
runBlocking {
    delay(1000L)
}

5.3 协程上下文与调度器

Dispatchers.Default // CPU 密集型工作
Dispatchers.IO     // IO 密集型工作
Dispatchers.Main   // UI 线程(Android)
Dispatchers.Unconfined // 不限制在任何特定线程

// 使用示例
launch(Dispatchers.IO) {
    // 网络请求或文件操作
}

5.4 协程取消

val job = launch {
    repeat(1000) { i ->
        ensureActive() // 检查是否取消
        println("job: I'm sleeping $i ...")
        delay(500L)
    }
}
delay(1300L)
job.cancelAndJoin()

六、Kotlin 最佳实践

6.1 代码风格

  1. 命名约定:

    • 类/对象:PascalCase

    • 函数/变量:camelCase

    • 常量:UPPER_SNAKE_CASE

  2. 格式化:

    • 4空格缩进

    • 类/函数之间空一行

    • 参数列表过长时换行

6.2 性能优化

  1. 内联小的高阶函数

  2. 避免不必要的对象创建

  3. 使用序列(Sequence)处理大数据集

  4. 注意协程的调度器选择

6.3 常见陷阱

  1. 空安全:

    val list: List<String> = emptyList()
    val firstItem = list.firstOrNull() // 安全
  2. 相等性:== 对应 equals(),=== 检查引用相等

  3. 初始化顺序:
class Example {
    val a = b + 1 // 错误:b 还未初始化
    val b = 2
}

      

Android Studio是一款由Google开发的集成开发环境(IDE),用于开发Android应用程序。而Kotlin是一种现代化的编程语言,它可以与Java无缝地集成在一起,并且在Android开发中越来越受欢迎。 关于Android Studio和Kotlin教程,以下是一些资源和步骤供您参考: 1. 安装Android Studio:首先,您需要下载并安装Android Studio。您可以从官方网站(https://developer.android.com/studio)上下载适用于您操作系统的版本,并按照安装向导进行安装。 2. 学习Kotlin语言:如果您对Kotlin还不熟悉,可以通过官方网站(https://kotlinlang.org/)上的文档和教程来学习Kotlin语言的基础知识。 3. 学习Android开发基础知识:在开始使用Android Studio和Kotlin进行开发之前,建议您先学习一些Android开发的基础知识,例如Android组件、布局、UI设计等。您可以通过官方文档(https://developer.android.com/guide)或在线教程来学习这些知识。 4. 学习使用Android Studio:一旦您对Android开发有了一定的了解,可以开始学习如何使用Android Studio进行开发。您可以通过官方文档(https://developer.android.com/studio/intro)或在线教程来学习Android Studio的使用方法和功能。 5. 学习使用Kotlin进行Android开发:一旦您熟悉了Android Studio的使用,可以开始学习如何使用Kotlin进行Android应用程序的开发。您可以通过官方文档(https://developer.android.com/kotlin)或在线教程来学习如何使用Kotlin进行Android开发
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值