Kotlin 语法速览

1. 变量和常量

  • val:不可变变量(只读,类似 final)
  • var:可变变量
  • 类型推断:Kotlin 支持自动推断变量类型
1
2
3
4
5
6
7
8
fun main() {
val name = "Alice" // 不可变,类型推断为 String
var age = 25 // 可变,类型推断为 Int
// name = "Bob" // 错误:val 不能重新赋值
age = 26 // 正确:var 可以重新赋值

println("Name: $name, Age: $age")
}

2. 基本数据类型

  • 常见类型:Int, Double, String, Boolean, List, Map
  • 无基本类型与引用类型的区分,全部是对象
1
2
3
4
5
6
7
8
fun main() {
val integer: Int = 42
val double: Double = 3.14
val text: String = "Kotlin"
val isActive: Boolean = true

println("Int: $integer, Double: $double, String: $text, Boolean: $isActive")
}

3. 控制流:if 表达式

  • if 在 Kotlin 中是表达式,可以返回值
  • 替代三元运算符(Kotlin 无三元运算符)
1
2
3
4
5
6
7
8
9
10
11
fun main() {
val score = 85
val grade = if (score >= 90) {
"A"
} else if (score >= 80) {
"B"
} else {
"C"
}
println("Score: $score, Grade: $grade")
}

4. 控制流:when 表达式

  • 类似 switch,但更强大,支持多种条件
  • 也是表达式,可返回值
1
2
3
4
5
6
7
8
9
10
fun main() {
val day = 3
val dayName = when (day) {
1 -> "Monday"
2 -> "Tuesday"
3 -> "Wednesday"
else -> "Unknown"
}
println("Day $day is $dayName")
}

5. 循环

  • for:用于迭代集合或范围
  • whiledo-while:与 Java 类似
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun main() {
// for 循环
println("Numbers 1 to 5:")
for (i in 1..5) {
print("$i ")
}
println()

// while 循环
var count = 3
println("Counting down:")
while (count > 0) {
print("$count ")
count--
}
}

6. 函数

  • 使用 fun 关键字
  • 支持默认参数、命名参数、单表达式函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 带默认参数的函数
fun greet(name: String, greeting: String = "Hi"): String {
return "$greeting, $name!"
}

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

// 高阶函数
fun apply(x: Int, op: (Int) -> Int) = op(x)
fun double(x: Int): Int = x * 2

fun main() {
// 调用函数
println(greet("Alice"))
println(greet("Bob", "Hello"))

println(sum(3, 5))

println(apply(5) { it * 2 }) // 10,等价于 apply(5, { it * 2 })
println(apply(5) { x: Int -> x * 2 }) // 完整形式
println(apply(5, ::double)) // 输出 10
}

7. 类和对象

  • 使用 class 定义类
  • 属性自动生成 getter/setter
  • 支持构造函数、主构造函数、初始化块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Person(val name: String) { // 主构造函数
private val secret = 42
protected val subclassVisible = "Protected"
internal val moduleVisible = "Internal"

var age: Int = 0
get() = field
set(value) {
if (value >= 0) field = value
}

init { // 初始化块
println("Person created: $name")
}

constructor(name: String, age: Int) : this(name) {
this.age = age
}

fun introduce() {
println("Hi, I'm $name, $age years old.")
}

fun getAgeAfterYears(years: Int): Int {
return age + years
}
}

fun main() {
val person = Person("Alice", 25)
person.introduce()
println("Age in 5 years: ${person.getAgeAfterYears(5)}")
}

8. 继承和接口

  • 默认类是 final,需用 open 允许继承
  • 接口使用 interface,实现用 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface Animal {
fun makeSound()
}

open class Pet(val name: String) // 使用 val 或者 var 把 name 声明为属性

class Dog(name: String) : Pet(name), Animal { // 这里的 name 只是构造函数的参数,不是属性
override fun makeSound() {
println("$name says Woof!")
}
}

abstract class Shape {
abstract fun area(): Double
}

class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
}

fun main() {
val dog = Dog("Buddy")
dog.makeSound()
}

9. 空安全

  • 可空类型用 ? 表示
  • 安全调用 ?.,Elvis 运算符 ?:,非空断言 !!
1
2
3
4
5
6
7
8
9
10
11
fun main() {
val nullableString: String? = null
// 安全调用
println("Length: ${nullableString?.length}")
// Elvis 运算符
val length = nullableString?.length ?: 0
// val length = nullableString?.length ?: throw IllegalArgumentException("nullableString 不能为空")
println("Length with Elvis: $length")
// 非空断言(小心使用)
// val length2 = nullableString!!.length // 会抛出 NullPointerException
}

10. 集合

  • 支持 List, Set, Map
  • 提供不可变和可变集合:listOf, mutableListOf
1
2
3
4
5
6
7
8
9
10
fun main() {
val numbers = listOf(1, 2, 3, 4)
val mutableList = mutableListOf("apple", "banana")
val map = mapOf(1 to "one", 2 to "two")

println("Numbers: $numbers")
mutableList.add("orange")
println("Mutable List: $mutableList")
println("Map: $map")
}

11. Lambda 表达式和匿名函数

  • Lambda 语法:{ 参数 -> 表达式 }
  • 常用于集合操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
// Lambda 过滤
val evenNumbers = numbers.filter { it % 2 == 0 } // it 是 lambda 表达式的默认参数名,仅在 lambda 有一个参数时才可用
println("Even numbers: $evenNumbers")

// Lambda 映射
val squared = numbers.map { x -> x * x } // 手动制定参数名为 x,也可以写成 { it * it }
println("Squared: $squared")

// 多参数必须显式命名
val map = mapOf("a" to 1, "b" to 2)
map.forEach { key, value -> println("$key=$value") }

// 函数引用简写
val names = listOf("Tom", "Alice", "Bob")
names.forEach(::println) // ::println 等价于 { name -> println(name) }

// 匿名函数
val f1 = fun(x: Int): Int { return x + 1 }
val f2 = { x: Int -> x + 1 }
val f3 = { x: Int -> println(x + 1) }
val f4 : (Int) -> Unit = { x -> println(x + 1) }
}

12. 扩展函数

  • 为现有类添加方法,无需继承
1
2
3
4
5
6
7
8
9
10
11
12
13
// 扩展函数
fun String.reverse(): String {
return this.reversed()
}

fun String.addExclamation() = "$this!"

fun main() {
val text = "Kotlin"
println(text.reverse())

println("Hello".addExclamation()) // Hello!
}

13. 数据类

  • 使用 data class 自动生成 toString, equals, hashCode 等,主构造函数至少一个参数,不可被 open
1
2
3
4
5
6
7
8
data class User(val name: String, val age: Int)

fun main() {
val user1 = User("Alice", 25)
val user2 = User("Alice", 25)
println("User1: $user1")
println(user.copy(name = "Bob"))
}

14. 协程

  • 用于异步编程,需引入 kotlinx.coroutines
  • 使用 launchasync 启动协程
1
2
3
4
5
6
7
8
9
10
11
12
13
import kotlinx.coroutines.*

fun main() {
val suspendFunc: suspend () -> Unit = { println("Suspended") }
// 运行协程
runBlocking {
launch {
delay(1000)
println("Hello from coroutine!")
}
println("Main thread continues")
}
}

注意:协程示例需要添加 kotlinx-coroutines-core 依赖到项目中,否则无法运行。

15. 对象声明

使用 object 创建单例

1
2
3
4
5
6
7
object Singleton {
fun hello() = println("Hello")
}

fun main() {
Singleton.hello() // Hello
}

16. 伴生对象

在类中使用 companion object 定义静态成员

1
2
3
4
5
6
7
8
9
class MyClass {
companion object { // 相当于静态方法/字段,提供类级别的静态成员支持
fun create() = MyClass() // 伴生对象中的工厂函数
}
}

fun main() {
val instance = MyClass.create()
}

等价于

1
2
3
4
5
public class MyClass {
public static MyClass create() {
return new MyClass();
}
}

17. 导入

1
2
3
4
import kotlin.math.PI as MathPI
fun main() {
println(MathPI) // 3.141592653589793
}

18. 异常处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
fun validate(x: Int) {
if (x < 0) throw IllegalArgumentException("Negative not allowed")
}

fun main() {
val result = try {
validate(-1)
"Success"
} catch (e: IllegalArgumentException) {
println("Error: ${e.message}")
"Failed"
} finally {
println("Cleanup")
}
println("Result: $result") // Failed
}

19. 泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Box<T>(val value: T) // 泛型类

fun <T> printItem(item: T) = println(item) // 泛型函数

interface Producer<out T> { // 使用协变 out 限制类型只能作为返回值
fun produce(): T
}
class StringProducer : Producer<String> {
override fun produce() = "Hello"
}

interface Consumer<in T> { // 使用逆变 in 限制类型只能作为参数
fun consume(item: T)
}
class AnyConsumer : Consumer<Any> {
override fun consume(item: Any) = println(item)
}

fun printList(list: List<*>) = println(list) // 通配符 *,类型为 Any?

fun main() {
val intBox = Box(42)
val strBox = Box("Kotlin")
println("${intBox.value}, ${strBox.value}")

printItem(42) // 42
printItem("Kotlin") // Kotlin

val producer: Producer<String> = StringProducer()
println(producer.produce())

val consumer: Consumer<Any> = AnyConsumer()
consumer.consume("Hello")

printList(listOf(1, "A")) // [1, A]
}

20. 自定义注解

1
2
3
4
5
6
7
8
annotation class MyAnnotation(val priority: Int)

@MyAnnotation(1)
fun annotated() = println("Annotated")

fun main() {
annotated()
}

21. 中缀函数

1
2
3
4
5
infix fun Int.plus(x: Int) = this + x // 表达式函数体 = 允许类型推断,代码块函数体 {} 必须显式写出返回类型

fun main() {
println(5 plus 3) // 8
}

22. 运算符重载

1
2
3
4
5
6
7
8
9
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
}

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

23. 内联类(已废弃)

  • 使用 inline class 定义单值包装类,编译时展开为原始类型,避免对象分配。
  • 不支持接口实现。
  • 使用 @JvmInline value class 替代 inline class
  • 不可扩展,不可被集成。
1
2
3
4
5
6
inline class Name(val value: String)

fun main() {
val name = Name("Kotlin")
println(name.value) // Kotlin
}

内联类和内联值类特性:

能做吗 描述
❌ 继承类 不行,value class 不能继承任何类(除了 Any
❌ 被继承 不行,value class 自身也不能被继承
✅ 实现接口 可以实现接口
✅ 内联优化 可以提升性能,避免创建对象

24. 内联值类

  • 场景:当需要包装单一值并保持性能(如 ID、计数、单位类型),使用内联值类;复杂对象仍使用普通 data class
  • 为什么不直接使用原始类型?
    • 内联值类为原始类型添加语义,防止误用。
    • 代码可读性增加。
    • 内联值类允许为原始类型添加方法或实现接口,封装特定逻辑,而不增加运行时开销。
    • 领域驱动设计(DDD)。在复杂系统中,内联值类支持领域建模,用类型区分不同概念(如 OrderId vs ProductId),提高代码一致性。
    • 内联值类可以在构造时验证值,防止非法状态,而原始类型无法限制。
    • 内联值类通过 @JvmInline 在编译时替换为底层原始类型(如 Int),几乎无额外内存或性能开销,接近直接使用原始类型的效率。
1
2
3
4
5
6
7
8
9
10
11
@JvmInline
value class UserId(val id: Int) : Comparable<UserId> {
override fun compareTo(other: UserId): Int = id.compareTo(other.id)
}

fun main() {
val userId = UserId(42)
println(userId.id) // 输出 42
println(userId > UserId(40)) // 输出 true
// 编译后,userId 被替换为 Int,支持接口方法
}

25. 无符号整数

  • UInt:32 位无符号整数,ULong:64 位,加 uU 后缀。
  • 编译为有符号整数,运行时模拟无符号行为。
1
2
3
4
5
fun main() {
val uint: UInt = 42u
val ulong: ULong = 123UL
println("$uint, $ulong")
}

26. SAM 转换改进

单方法接口支持 Lambda 转换

1
2
3
4
5
6
7
8
fun interface Action {
fun run()
}

fun main() {
val action = Action { println("Run") }
action.run()
}

27. 密封接口和密封类

  • sealed 修饰符表示 Expr接口(或类)只能在同一模块(通常是同一文件或项目)内被实现。
  • 外部代码无法创建新的Expr子类,确保Expr的所有可能实现(如Num)是已知的。
  • 对比普通接口,sealed 减少了运行时类型转换(如 as Num)的需要。
  • 意义:保证类型系统的封闭性,防止意外扩展,适合建模有限的类型集合(如表达式树)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sealed interface Expr

data class Num(val value: Int) : Expr {
operator fun plus(other: Num) = Num(value + other.value)
}

data class Add(val left: Num, val right: Num) : Expr

fun main() {
val expr1: Expr = Num(42)
println((expr1 as Num).value) // 不够优雅
val expr2: Expr = Add(Num(2), Num(3))
println(
when (expr2) {
is Add -> (expr2.left + expr2.right)
is Num -> expr2.value
}
)
}

Kotlin 的 密封类(sealed class) 是一种用于表示受限继承结构的类,适合用来表达有限状态、事件、指令等类型的场景。sealed class 表示一个封闭的类层次结构,所有子类必须定义在同一个文件中。它是 抽象类 的一种变体,用于替代 enum 或 if/else 的分支判断,且能结合 when 表达式使用,非常强大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
sealed class Result<out T> {
data class Success<out T>(val data: T) : Result<T>()
data class Error(val exception: Throwable) : Result<Nothing>()
object Loading : Result<Nothing>()
}

fun fetchData(): Result<String> {
return try {
val result = "Hello"
Result.Success(result)
} catch (e: Exception) {
Result.Error(e)
}
}

fun handle(result: Result<String>) {
when (result) {
is Result.Success -> println("Got data: ${result.data}")
is Result.Error -> println("Error: ${result.exception.message}")
Result.Loading -> println("Loading...")
}
}

inline fun <T> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
if (this is Result.Success) action(data)
return this
}

inline fun <T> Result<T>.onError(action: (Throwable) -> Unit): Result<T> {
if (this is Result.Error) action(exception)
return this
}

fetchData()
.onSuccess { println("Success: $it") }
.onError { println("Error: ${it.message}") }

👉 由于 Result 是密封类,when 表达式必须覆盖所有子类,否则编译报错(如果没有 else 分支)。

28. IO

1
2
3
4
5
import java.io.File
fun main() {
File("test.txt").writeText("Hello")
println(File("test.txt").readText()) // Hello
}

29. 反射和运行时

需要在build.gradle.kts文件中添加:

1
2
3
dependencies {
implementation(kotlin("reflect"))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
fun hello() = println("Hello")

data class Person(val name: String)

fun main() {
val ref1 = String::class // 类引用
println(ref1.simpleName) // String

val ref2 = ::hello // 函数引用,仅限顶层或成员函数
ref2() // Hello

val props = Person::class.members
println(props.map { it.name }) // [name]
}

30. 属性委托

  • 使用by将属性委托给代理对象
  • lazy首次访问时初始化,不可重新赋值。默认同步,需明确模式(如 LazyThreadSafetyMode.NONE)。
  • Delegates.observable:属性变化监听。
  • lazyobservableKotlin 提供的内置委托。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import kotlin.properties.Delegates
fun main() {
// lazy
val lazyVal: String by lazy {
println("Computed")
"Lazy"
}
println(lazyVal) // Computed, Lazy
println(lazyVal) // Lazy(不再计算)

// observable
var obsVal: String by Delegates.observable("Init") {
property, old, new -> println("${property.name}: $old -> $new")
}
obsVal = "New" // obsVal: Init -> New
obsVal = "Final" // obsVal: New -> Final
}

31. 类委托

  • 使用by将接口实现委托给对象
  • 组合优于继承,使用委托组合多个对象的行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
interface Printer {
fun printMessage(message: String)
}

class ConsolePrinter : Printer {
override fun printMessage(message: String) {
println("Console: $message")
}
}

class DelegatingPrinter(private val printer: Printer) : Printer by printer {
// 可选择重写部分方法
override fun printMessage(message: String) {
println("Delegating: $message") // 这里是装饰器模式,包装现有实现,添加额外功能(如日志、验证)
printer.printMessage(message) // 调用委托对象
}
}

fun main() {
val consolePrinter = ConsolePrinter()
// 这里可以通过更换委托对象,动态改变行为。例如:切换 Printer 实现为文件打印或网络打印
val delegatingPrinter = DelegatingPrinter(consolePrinter)
delegatingPrinter.printMessage("Hello, Kotlin!") // 输出:
// Delegating: Hello, Kotlin!
// Console: Hello, Kotlin!
}

32. 作用域函数

Kotlin 的作用域函数(Scope Functions)是让你能更优雅地处理对象初始化、配置、临时作用域和链式调用的语法工具。常用的有以下 5 个:

函数 用途简记 返回值 引用名
let null安全、链式处理 Lambda结果 it
run 初始化 + 返回值 Lambda结果 this
with 多操作 + 返回值 Lambda结果 this
apply 初始化 + 返回对象 原对象 this
also 调试副作用 + 返回对象 原对象 it

🔹 1. let:用 it 作为对象引用

适合做null 检查和链式操作。

1
2
3
4
val name: String? = "Kotlin"
name?.let {
println("名字是 $it") // it 指向 name
}

🔹 2. run:用 this 引用对象,返回表达式结果

适合对象初始化 + 返回值计算

1
2
3
4
5
val length = "Kotlin".run {
println("字符串是 $this")
length // 返回最后一行,即 length 的值
}
println(length) // 6

🔹 3. with:不是扩展函数,作用于已有对象

适合对对象做多个操作但不返回原对象,而是返回表达式值。

1
2
3
4
5
6
7
val sb = StringBuilder()
val result = with(sb) {
append("Hello, ")
append("World!")
toString()
}
println(result) // Hello, World!

🔹 4. apply:用 this,返回对象自身

适合构造对象并链式设置属性

1
2
3
4
5
6
7
8
data class User(var name: String = "", var age: Int = 0)

fun main() {
val user = User().apply {
name = "124"
age = 25
}
}

🔹 5. also:用 it,返回对象自身

适合用于链式调用中插入副作用逻辑(如日志、调试)

1
2
3
4
val list = mutableListOf(1, 2, 3)
.also { println("原始列表: $it") }
.apply { add(4) }
.also { println("添加元素后: $it") }

33. 内联函数

关键字 意义
inline 函数和 lambda 代码都在编译期被“展开复制”到调用处,提高性能
noinline 在 inline 函数中,禁止某个 lambda 被内联
crossinline 在 inline 函数中,禁止 lambda 使用 return 非局部返回

inline

✅ 1. inline:让函数和 lambda “展开” 到调用处,提高性能

1
2
3
4
5
6
7
8
9
10
11
inline fun doSomething(block: () -> Unit) {
println("Before block")
block() // 会被“复制粘贴”到调用处
println("After block")
}

fun main() {
doSomething {
println("Doing work")
}
}

编译后近似于 👇:

1
2
3
4
5
fun main() {
println("Before block")
println("Doing work")
println("After block")
}

✅ 优点:消除函数调用开销、避免创建 Function 对象(尤其在频繁调用的 lambda 中)


noinline

⚠️ 2. noinline:阻止某个 lambda 被内联(因为你可能要传递它)

1
2
3
4
5
6
7
8
inline fun doOps(
inlineBlock: () -> Unit,
noinline logging: () -> Unit // ❗ 禁止内联
) {
inlineBlock() // 内联
val func = logging // ❗ 如果不加 noinline 会编译错误,因为不能传递被内联的 lambda
func()
}

你必须加 noinline,否则无法将 lambda 存成变量或传给其他函数。


crossinline

🚫 3. crossinline:禁止 lambda 用 return 做“非局部返回”

🔸 默认情况下,内联 lambda 可以直接 return,但有风险。

1
2
3
4
5
6
7
8
9
10
11
inline fun higherOrder(block: () -> Unit) {
println("Before")
block()
println("After") // ⚠️ 如果 block 里直接 return,这行永远不会执行
}

fun test() {
higherOrder {
return // 🚫 这是“非局部返回”:会从 test() 函数直接返回
}
}

要禁止这种“跳出上层函数”的行为,加 crossinline

1
2
3
4
5
6
7
inline fun higherOrder(crossinline block: () -> Unit) {
println("Before")
val r = Runnable {
block() // ✅ 现在 block() 里面不能写 return 了
}
r.run()
}

✅ 总结对照表

关键字 用途说明
inline 将函数和 lambda 在调用处展开,提升性能、支持非局部 return
noinline 禁止某个 lambda 被内联(可传递为变量)
crossinline 禁止 lambda 使用非局部 return(可用在回调、线程等)

📌 什么时候用它们?

场景 关键字
高频调用、性能敏感的高阶函数 inline
lambda 需要传递或存为变量 noinline
lambda 不能用 return(如线程、回调) crossinline