Kotlin
语法树
graph LR
A[Kotlin 语法概览]
%% 1. 基础语法特性
A --> B[基础语法特性]
B --> B1[基本数据类型]
B1 --> B1a["整型: Byte, Short, Int, Long"]
B1 --> B1b["浮点型: Float, Double"]
B1 --> B1c["字符型: Char"]
B1 --> B1d["布尔型: Boolean"]
B --> B2[变量与常量]
B2 --> B2a["变量: var"]
B2 --> B2b["常量: val"]
B --> B3[运算符]
B3 --> B3a["算术运算符: +, -, *, /, %"]
B3 --> B3b["关系运算符: ==, !=, <, >, <=, >="]
B3 --> B3c["逻辑运算符: &&, ||, !"]
B3 --> B3d["位运算符: and, or, xor, shl, shr"]
B3 --> B3e["赋值运算符: =, +=, -=, *=, /="]
B3 --> B3f["其他: Elvis ?:, Safe Call ?., !!, in"]
B --> B4[控制结构]
B4 --> B4a["条件语句: if, else"]
B4 --> B4b["分支语句: when"]
B4 --> B4c["循环: for, while, do-while"]
B4 --> B4d["跳转: break, continue, return"]
B --> B5[函数]
B5 --> B5a["函数定义: fun"]
B5 --> B5b["参数: 默认参数, 可变参数 vararg"]
B5 --> B5c["单表达式函数: ="]
B5 --> B5d["匿名函数"]
B5 --> B5e["高阶函数"]
B --> B6[类与对象]
B6 --> B6a["类定义: class"]
B6 --> B6b["构造函数: constructor"]
B6 --> B6c["属性: var, val"]
B6 --> B6d["访问控制: public, private, protected, internal"]
B6 --> B6e["继承: open, :"]
B6 --> B6f["接口: interface"]
B6 --> B6g["抽象类: abstract"]
B6 --> B6h["数据类: data"]
B6 --> B6i["对象声明: object"]
B6 --> B6j["伴生对象: companion object"]
B --> B7[包与导入]
B7 --> B7a["包定义: package"]
B7 --> B7b["导入: import"]
B --> B8[异常处理]
B8 --> B8a["try, catch, finally"]
B8 --> B8b["throw"]
B --> B9[泛型]
B9 --> B9a["泛型类: <T>"]
B9 --> B9b["泛型函数"]
B9 --> B9c["协变: out"]
B9 --> B9d["逆变: in"]
B9 --> B9e["通配符: *"]
B --> B10[空安全]
B10 --> B10a["可空类型: ?"]
B10 --> B10b["安全调用: ?."]
B10 --> B10c["Elvis 操作符: ?:"]
B10 --> B10d["非空断言: !!"]
B --> B11[注解]
B11 --> B11a["内置注解: @Deprecated, @Suppress"]
B11 --> B11b["自定义注解: annotation"]
%% 2. 现代 Kotlin 新特性
A --> C[现代 Kotlin 新特性]
C --> C1[Kotlin 1.0+]
C1 --> C1a["Lambda 表达式: { x -> x * 2 }"]
C1 --> C1b["扩展函数"]
C1 --> C1c["中缀函数: infix"]
C1 --> C1d["运算符重载: operator"]
C --> C2[Kotlin 1.1]
C2 --> C2a["协程: suspend, launch"]
C --> C3[Kotlin 1.3]
C3 --> C3a["内联类: inline class"]
C3 --> C3b["无符号整数: UInt, ULong"]
C --> C4[Kotlin 1.4]
C4 --> C4a["SAM 转换改进"]
C4 --> C4b["尾随逗号"]
C --> C5[Kotlin 1.5]
C5 --> C5a["密封接口: sealed interface"]
C5 --> C5b["内联值类: value class"]
C --> C6[Kotlin 1.6]
C6 --> C6a["挂起函数类型: suspend () -> Unit"]
C --> C7[Kotlin 1.8]
C7 --> C7a["上下文接收者: context"]
C --> C8[Kotlin 1.9+]
C8 --> C8a["多平台改进"]
C8 --> C8b["K2 编译器特性"]
%% 3. 其他特性
A --> D[其他特性]
D --> D1[标准库扩展]
D1 --> D1a["集合: List, Set, Map"]
D1 --> D1b["字符串: String, StringBuilder"]
D1 --> D1c["IO: java.io"]
D1 --> D1d["并发: kotlin.coroutines"]
D --> D2[反射与运行时]
D2 --> D2a["类引用: ::class"]
D2 --> D2b["函数引用: ::function"]
D2 --> D2c["反射库: kotlin.reflect"]
D --> D3[委托]
D3 --> D3a["属性委托: by lazy, by Delegates"]
D3 --> D3b["类委托: by"]
详解
一、基础语法特性
1. 基本数据类型
1.1 整型:Byte
,
Short
, Int
, Long
- 语法说明:
Byte
:8 位有符号整数,范围-128
到127
,显式声明为Byte
。Short
:16 位有符号整数,范围-32768
到32767
,显式声明为Short
。Int
:32 位有符号整数,范围-2,147,483,648
到2,147,483,647
,默认整数类型。Long
:64 位有符号整数,范围-9,223,372,036,854,775,808
到9,223,372,036,854,775,807
,需加L
后缀。- 支持类型推断,如
val x = 42
推断为Int
。
- 应用场景:
Byte
:节省内存,适用于小型数据(如网络协议中的标志位、图像像素值)。Short
:较少使用,适用于特定硬件接口或与旧系统交互。Int
:日常计数、数组索引、循环变量。Long
:大范围数据,如时间戳(毫秒)、文件大小、数据库 ID。
- 底层原理:
- 在 JVM 上,分别映射为 Java 的
byte
、short
、int
、long
,为原始类型以优化性能。 - 当声明为可空类型(如
Int?
)或用于泛型时,装箱为java.lang.Byte
、Short
、Integer
、Long
。 - 编译器优化字面量,例如
val x = 42
使用int
,避免不必要的对象创建。 - 类型转换需显式调用方法(如
toInt()
),避免隐式转换错误。
- 在 JVM 上,分别映射为 Java 的
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19fun main() {
val byte: Byte = 127
val short: Short = 32_767
val int: Int = 2_147_483_647
val long: Long = 9_223_372_036_854_775_807L
println("Byte: $byte, Short: $short, Int: $int, Long: $long")
// 类型转换
val byteToInt: Int = byte.toInt()
println("Byte to Int: $byteToInt") // 127
// 溢出示例
val overflow: Byte = (byte + 1).toByte() // 127 + 1 = -128(溢出)
println("Overflow Byte: $overflow")
// 可空类型
val nullableLong: Long? = null
println("Nullable Long: $nullableLong")
} - 注意事项:
- 溢出风险:
Byte
和Short
操作超出范围不会自动提升类型,需手动转换(如(byte + 1).toByte()
),否则溢出(如 127 + 1 = -128)。 - 类型转换:必须显式转换(如
toInt()
),否则编译错误,避免隐式转换导致的意外。 - 性能:优先使用
Int
,因为它是 JVM 的默认整数类型,Byte
和Short
在某些场景可能因装箱而降低性能。 L
后缀:Long
字面量忘记加L
会默认推断为Int
,可能导致溢出。
- 溢出风险:
1.2 浮点型:Float
,
Double
- 语法说明:
Float
:32 位单精度浮点数,约 6-7 位有效数字,需加f
或F
后缀(如3.14f
)。Double
:64 位双精度浮点数,约 15-16 位有效数字,默认浮点类型(如3.14
)。- 支持科学计数法(如
1.23e-4
)。
- 应用场景:
Float
:节省内存,适用于图形渲染(如 OpenGL 坐标)、低精度计算。Double
:高精度计算,如科学计算、财务数据处理、地理坐标。
- 底层原理:
- 遵循 IEEE 754 标准,包含 1 位符号、指数位(
Float
8 位,Double
11 位)和尾数位(Float
23 位,Double
52 位)。 - 在 JVM 上,
Float
映射为float
,Double
映射为double
,可空时装箱为java.lang.Float
和Double
。 - 运算结果可能因舍入而有微小误差。
- 遵循 IEEE 754 标准,包含 1 位符号、指数位(
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19fun main() {
val float: Float = 3.14159f
val double: Double = 3.141592653589793
println("Float: $float, Double: $double")
// 科学计数法
val sciFloat: Float = 1.23e2f // 123.0
println("Scientific Float: $sciFloat")
// 精度问题
val sumFloat = 0.1f + 0.2f
println("Float 0.1 + 0.2 = $sumFloat") // 0.300000004(误差)
val sumDouble = 0.1 + 0.2
println("Double 0.1 + 0.2 = $sumDouble") // 0.30000000000000004(更高精度)
// 类型转换
val floatToDouble: Double = float.toDouble()
println("Float to Double: $floatToDouble")
} - 注意事项:
- 精度问题:浮点运算可能有舍入误差(如
0.1 + 0.2 != 0.3
),避免直接用==
比较,建议用范围检查(如abs(a - b) < 0.0001
)。 f
后缀:Float
字面量忘记加f
会推断为Double
,导致类型不匹配。- 性能与内存:
Float
节省内存,但精度低,Double
更适合高精度需求。 - 溢出与无穷:除以 0 返回
Infinity
而非异常,需检查结果。
- 精度问题:浮点运算可能有舍入误差(如
1.3 字符型:Char
- 语法说明:
- 表示 16 位 Unicode 字符,使用单引号定义(如
'A'
)。 - 支持转义字符(如
\n
,\t
)和 Unicode 码点(如\u0041
表示'A'
)。
- 表示 16 位 Unicode 字符,使用单引号定义(如
- 应用场景:
- 文本解析(如逐字符处理字符串)。
- 表示单个按键输入或编码转换。
- 底层原理:
- 映射到 JVM 的
char
,存储为 16 位无符号整数(0 到 65535)。 - 可空时装箱为
java.lang.Character
。 - 支持与整数运算,基于 Unicode 码点。
- 映射到 JVM 的
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17fun main() {
val char: Char = 'K'
val unicodeChar: Char = '\u004B' // 'K'
println("Char: $char, Unicode: $unicodeChar, Code: ${char.code}") // K, K, 75
// 转义字符
val newline: Char = '\n'
print("Line1${newline}Line2") // Line1换行Line2
// 字符运算
val nextChar = char + 1 // 'L'
println("Next Char: $nextChar") // L
// 可空类型
val nullableChar: Char? = null
println("Nullable Char: $nullableChar")
} - 注意事项:
- 与数字区分:
Char
不能直接当作整数使用,需用.code
转换。 - 单引号:使用双引号(如
"A"
)会推断为String
,导致类型错误。 - 范围限制:超出 Unicode 范围(如
\uFFFF
以上)无效。 - 运算结果:
Char
加减返回Int
,需转换回Char
。
- 与数字区分:
1.4 布尔型:Boolean
- 语法说明:
- 表示
true
或false
,用于逻辑判断。 - 可声明为可空类型(如
Boolean?
)。
- 表示
- 应用场景:
- 条件判断(如
if
语句)。 - 状态标志(如
isActive
)。 - 三态逻辑(true, false, null)。
- 条件判断(如
- 底层原理:
- 映射到 JVM 的
boolean
,占用 1 位(实际实现可能占 1 字节)。 - 可空时装箱为
java.lang.Boolean
。 - 逻辑运算基于短路求值。
- 映射到 JVM 的
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17fun main() {
val isActive: Boolean = true
val isDone: Boolean? = null
println("isActive: $isActive, isDone: $isDone")
// 逻辑运算
val result = isActive && (isDone ?: false)
println("Result: $result") // false
// 三态逻辑
val status = when (isDone) {
true -> "Completed"
false -> "Pending"
null -> "Unknown"
}
println("Status: $status") // Unknown
} - 注意事项:
- 可空处理:
Boolean?
在逻辑运算中需配合?:
或!!
,否则编译错误。 - 短路求值:
&&
和||
是短路的,避免在右边放入副作用代码。 - 性能:避免不必要的装箱(如
Boolean?
),影响效率。
- 可空处理:
2. 变量与常量
2.1 变量:var
- 语法说明:
- 使用
var
关键字声明可变变量,可多次赋值。 - 支持类型推断(如
var x = 10
推断为Int
),或显式声明(如var x: Int = 10
)。
- 使用
- 应用场景:
- 循环计数器、临时状态存储。
- 用户输入或动态数据处理。
- 底层原理:
- 编译为 JVM 的普通局部变量或字段,分配内存后可自由修改。
- 类型推断在编译时完成,生成对应的字节码类型(如
int
)。 - 不涉及运行时开销。
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18fun main() {
var count = 10
println("Initial: $count") // 10
count = 20
println("Updated: $count") // 20
// 类型显式声明
var name: String = "Kotlin"
name = "Java"
println("Name: $name") // Java
// 作用域示例
run {
var local = 5
local += 1
println("Local: $local") // 6
}
} - 注意事项:
- 过度使用:滥用
var
增加可变性,降低代码安全性,建议优先用val
。 - 类型一致性:赋值时类型必须匹配,否则编译错误。
- 作用域:局部变量未初始化不会报错,但使用前需赋值。
- 过度使用:滥用
2.2 常量:val
- 语法说明:
- 使用
val
关键字声明只读变量,赋值后不可更改引用。 - 支持类型推断和显式声明。
- 可用于表达式返回值。
- 使用
- 应用场景:
- 常量定义(如数学常数
PI
)。 - 函数结果缓存、不可变配置。
- 常量定义(如数学常数
- 底层原理:
- 编译为 JVM 的
final
变量,确保引用不可变。 - 对于对象,
val
只限制引用,对象内部状态可通过方法修改。 - 若为基本类型,编译器可能内联值以优化性能。
- 编译为 JVM 的
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15fun main() {
val pi = 3.14
// pi = 3.15 // 错误:val 不可重新赋值
println("Pi: $pi")
// 可变对象
val list = mutableListOf(1, 2)
list.add(3)
println("List: $list") // [1, 2, 3]
// 表达式赋值
val x = 5
val max = if (x > 0) x else 0
println("Max: $max") // 5
} - 注意事项:
- 引用 vs 对象:
val
只限制引用,对象内容可变,需区分。 - 初始化:必须初始化或在
init
块中赋值,否则编译错误。 - 性能:编译器可能内联
val
,但复杂表达式不会。
- 引用 vs 对象:
3. 运算符
3.1 算术运算符:+
, -
,
*
, /
, %
- 语法说明:
+
:加法或字符串拼接。-
:减法。*
:乘法。/
:除法(整数除法结果为整数,浮点除法为浮点数)。%
:取模。
- 应用场景:
- 数学计算(如统计、物理模拟)。
- 字符串拼接(如日志生成)。
- 底层原理:
- 映射到 JVM 的数学指令(如
iadd
,fdiv
)。 - 字符串
+
编译为StringBuilder
操作。 - 除法对整数和浮点分开处理。
- 映射到 JVM 的数学指令(如
- 示例代码:
1
2
3
4
5
6
7
8
9
10fun main() {
val a = 10
val b = 3
println("a + b = ${a + b}") // 13
println("a - b = ${a - b}") // 7
println("a * b = ${a * b}") // 30
println("a / b = ${a / b}") // 3 (整数除法)
println("a % b = ${a % b}") // 1
println("Hello " + "World") // Hello World
} - 注意事项:
- 除以零:整数除以 0 抛
ArithmeticException
,浮点返回Infinity
。 - 类型提升:操作数类型不同时提升到更高精度(如
Int + Double
结果为Double
)。 - 字符串拼接性能:大量
+
操作效率低,建议用模板或StringBuilder
。
- 除以零:整数除以 0 抛
3.2 关系运算符:==
, !=
,
<
, >
, <=
,
>=
- 语法说明:
==
:值相等。!=
:值不等。<
,>
:小于、大于。<=
,>=
:小于等于、大于等于。===
,!==
:引用相等/不等。
- 应用场景:
- 条件判断、排序算法。
- 底层原理:
==
调用equals()
,===
检查对象引用。- 其他运算符映射到 JVM 比较指令(如
if_icmplt
)。
- 示例代码:
1
2
3
4
5
6
7
8
9
10fun main() {
val x = 5
val y = 10
println("x == y: ${x == y}") // false
println("x < y: ${x < y}") // true
val str1 = "Kotlin"
val str2 = "Kotlin"
println("str1 === str2: ${str1 === str2}") // true (字符串池)
} - 注意事项:
- 浮点比较:避免直接用
==
,因精度误差可能导致错误。 ===
使用:仅适用于对象引用,基本类型始终用==
。- 自定义类:
==
需要重写equals()
。
- 浮点比较:避免直接用
3.3 逻辑运算符:&&
,
||
, !
- 语法说明:
&&
:逻辑与,短路求值。||
:逻辑或,短路求值。!
:逻辑非。
- 应用场景:
- 多条件组合判断。
- 底层原理:
- 短路求值优化性能,映射到 JVM 逻辑指令。
- 示例代码:
1
2
3
4
5
6
7fun main() {
val a = true
val b = false
println("a && b: ${a && b}") // false
println("a || b: ${a || b}") // true
println("!a: ${!a}") // false
} - 注意事项:
- 副作用:短路求值可能跳过右边代码,注意逻辑顺序。
- 可空类型:
Boolean?
需处理null
。
3.4 位运算符:and
,
or
, xor
, shl
,
shr
- 语法说明:
and
:按位与。or
:按位或。xor
:按位异或。shl
:左移。shr
:右移(带符号)。
- 应用场景:
- 权限标志、位掩码、低级优化。
- 底层原理:
- 映射到 JVM 位操作指令(如
iand
,ishl
)。
- 映射到 JVM 位操作指令(如
- 示例代码:
1
2
3
4
5
6
7
8
9fun main() {
val x = 5 // 101
val y = 3 // 011
println("x and y: ${x and y}") // 1 (001)
println("x or y: ${x or y}") // 7 (111)
println("x xor y: ${x xor y}") // 6 (110)
println("x shl 1: ${x shl 1}") // 10 (1010)
println("x shr 1: ${x shr 1}") // 2 (010)
} - 注意事项:
- 符号位:
shr
是带符号右移,负数需注意。 - 溢出:移位不检查范围,可能导致意外结果。
- 符号位:
3.5 赋值运算符:=
, +=
,
-=
, *=
, /=
- 语法说明:
=
:简单赋值。+=
,-=
,*=
,/=
:组合赋值。
- 应用场景:
- 累加操作、状态更新。
- 底层原理:
- 编译为赋值和计算的组合指令。
- 示例代码:
1
2
3
4
5
6
7fun main() {
var x = 10
x += 5
println("x += 5: $x") // 15
x *= 2
println("x *= 2: $x") // 30
} - 注意事项:
- 不可变变量:
val
不支持赋值运算符。 - 类型匹配:右边类型需与左边兼容。
- 不可变变量:
3.6 其他运算符:?:
,
?.
, !!
, in
- 语法说明:
?:
(Elvis):若左边为null
,返回右边值。?.
:安全调用,若对象为null
返回null
。!!
:非空断言,若为null
抛异常。in
:检查是否在范围或集合中。
- 应用场景:
- 空安全处理、范围检查。
- 底层原理:
- 编译器插入
null
检查和跳转逻辑。
- 编译器插入
- 示例代码:
1
2
3
4
5
6
7fun main() {
val str: String? = null
println("Safe call: ${str?.length}") // null
println("Elvis: ${str?.length ?: 0}") // 0
println("In range: ${3 in 1..5}") // true
// println(str!!.length) // 抛 NPE
} - 注意事项:
!!
风险:滥用可能抛NullPointerException
,尽量避免。- 性能:
?.
和?:
增加分支检查,频繁使用可能影响性能。 in
范围:范围对象需实现contains
。
4. 控制结构
4.1 条件语句:if
,
else
- 语法说明:
- 基本形式:
if (condition) { ... } else { ... }
。 - 可作为表达式,返回值由最后一行决定。
- 基本形式:
- 应用场景:
- 简单条件分支、返回值计算。
- 底层原理:
- 编译为 JVM 的
if
指令(如ifne
),表达式形式生成临时变量。
- 编译为 JVM 的
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13fun main() {
val x = 5
val result = if (x > 0) {
println("Positive")
"Positive"
} else if (x == 0) {
"Zero"
} else {
println("Negative")
"Negative"
}
println("Result: $result") // Positive
} - 注意事项:
- 完整性:作为表达式时必须有
else
,否则编译错误。 - 嵌套:过多嵌套降低可读性,考虑用
when
。
- 完整性:作为表达式时必须有
4.2 分支语句:when
- 语法说明:
- 替代
switch
,支持多种条件(如值匹配、范围检查、is
类型检查)。 - 可作为表达式。
- 替代
- 应用场景:
- 多条件分支、模式匹配。
- 底层原理:
- 编译为条件跳转或表查找(类似
switch
)。
- 编译为条件跳转或表查找(类似
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11fun main() {
val x = 2
val desc = when (x) {
1 -> "One"
2, 3 -> "Two or Three"
in 1..10 -> "In range"
is Int -> "Integer"
else -> "Other"
}
println("Description: $desc") // Two or Three
} - 注意事项:
- 覆盖性:作为表达式时需覆盖所有情况或加
else
。 - 性能:复杂条件可能生成较多字节码。
- 覆盖性:作为表达式时需覆盖所有情况或加
4.3 循环:for
,
while
, do-while
- 语法说明:
for
:for (item in collection/range) { ... }
,支持范围、步长。while
:while (condition) { ... }
。do-while
:do { ... } while (condition)
。
- 应用场景:
- 数据遍历、重复执行。
- 底层原理:
for
编译为迭代器调用,while
为条件跳转。
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14fun main() {
for (i in 1..5 step 2) print("$i ") // 1 3 5
println()
var x = 0
while (x < 3) {
print("$x ")
x++
} // 0 1 2
println()
do {
print("$x ")
x--
} while (x > 0) // 3 2 1
} - 注意事项:
- 范围对象:
for
需可迭代对象。 - 无限循环:
while (true)
需确保退出条件。
- 范围对象:
4.4 跳转:break
,
continue
, return
- 语法说明:
break
:退出循环。continue
:跳到下一次迭代。return
:返回函数结果。- 支持标签(如
break@label
)。
- 应用场景:
- 控制循环流程。
- 底层原理:
- 编译为
goto
或返回指令。
- 编译为
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13fun main() {
outer@ for (i in 1..3) {
for (j in 1..3) {
if (j == 2) break@outer
print("$i$j ")
}
} // 11
println()
for (i in 1..5) {
if (i == 3) continue
print("$i ") // 1 2 4 5
}
} - 注意事项:
- 标签:多重循环需正确使用标签,避免跳错。
- 可读性:过多跳转降低代码清晰度。
5. 函数
5.1 函数定义:fun
- 语法说明:
- 格式:
fun name(params): ReturnType { ... }
。 - 返回类型可选(类型推断)。
- 格式:
- 应用场景:
- 代码复用、逻辑封装。
- 底层原理:
- 编译为 JVM 方法,参数和返回值类型静态绑定。
- 示例代码:
1
2
3
4
5
6fun add(a: Int, b: Int): Int {
return a + b
}
fun main() {
println(add(3, 4)) // 7
} - 注意事项:
- 返回类型:复杂函数建议显式声明返回类型。
- 命名:遵循清晰命名规范。
5.2 参数:默认参数,
vararg
- 语法说明:
- 默认参数:
param: Type = defaultValue
。 vararg
:可变参数,接收任意数量参数。
- 默认参数:
- 应用场景:
- 简化函数调用、可变参数处理。
- 底层原理:
- 默认参数生成重载方法。
vararg
编译为数组参数。
- 示例代码:
1
2
3
4
5
6
7fun printItems(vararg items: String, prefix: String = ">") {
items.forEach { println("$prefix $it") }
}
fun main() {
printItems("A", "B", prefix = "#") // # A, # B
printItems("X") // > X
} - 注意事项:
- 顺序:默认参数应放在
vararg
后。 - 唯一性:一个函数只能有一个
vararg
。
- 顺序:默认参数应放在
5.3 单表达式函数:=
- 语法说明:
- 使用
=
替代{}
和return
,适用于简单函数。
- 使用
- 应用场景:
- 简洁计算、工具函数。
- 底层原理:
- 编译为普通方法,表达式直接作为返回值。
- 示例代码:
1
2
3
4fun multiply(a: Int, b: Int) = a * b
fun main() {
println(multiply(2, 3)) // 6
} - 注意事项:
- 可读性:复杂逻辑不适合单表达式。
- 类型推断:返回值类型需明确。
5.4 匿名函数
- 语法说明:
- 格式:
fun(params) = expression
,无函数名。
- 格式:
- 应用场景:
- 临时逻辑定义、函数变量。
- 底层原理:
- 编译为函数对象。
- 示例代码:
1
2
3
4fun main() {
val anon = fun(x: Int) = x * 2
println(anon(5)) // 10
} - 注意事项:
- 性能:频繁创建可能增加开销。
- 使用范围:适合局部使用。
5.5 高阶函数
- 语法说明:
- 函数参数或返回值为函数类型(如
(Int) -> Int
)。
- 函数参数或返回值为函数类型(如
- 应用场景:
- 回调、函数式编程。
- 底层原理:
- 编译为函数接口(如
Function1
),若加inline
则内联。
- 编译为函数接口(如
- 示例代码:
1
2
3
4fun apply(x: Int, op: (Int) -> Int) = op(x)
fun main() {
println(apply(5) { it * 2 }) // 10
} - 注意事项:
- 性能:未加
inline
会生成对象,影响效率。 - 类型复杂性:参数类型需清晰定义。
- 性能:未加
6. 类与对象
6.1 类定义:class
- 语法说明:
- 格式:
class Name(params) { ... }
,主构造函数在类头。
- 格式:
- 应用场景:
- 数据建模、面向对象设计。
- 底层原理:
- 编译为 JVM 类,构造函数生成
init
块。
- 编译为 JVM 类,构造函数生成
- 示例代码:
1
2
3
4
5
6
7class Person(val name: String) {
fun greet() = println("Hello, $name")
}
fun main() {
val p = Person("Alice")
p.greet() // Hello, Alice
} - 注意事项:
- 主构造函数:参数需明确作用(
val
/var
)。
- 主构造函数:参数需明确作用(
6.2 构造函数:constructor
- 语法说明:
- 主构造函数在类头,次构造函数使用
constructor
。
- 主构造函数在类头,次构造函数使用
- 应用场景:
- 对象初始化多样性。
- 底层原理:
- 次构造函数委托给主构造函数,编译为多个构造方法。
- 示例代码:
1
2
3
4
5
6
7
8class Person(val name: String) {
constructor(name: String, age: Int) : this(name) {
println("Age: $age")
}
}
fun main() {
Person("Alice", 25) // Age: 25
} - 注意事项:
- 委托:次构造函数必须调用主构造函数。
- 复杂度:过多构造函数降低可读性。
6.3 属性:var
, val
- 语法说明:
var
定义可变属性,val
定义只读属性。- 可自定义
get
/set
。
- 应用场景:
- 对象状态管理。
- 底层原理:
- 编译为字段和访问器方法。
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12class Box {
var size: Int = 0
get() = field
set(value) {
if (value >= 0) field = value
}
}
fun main() {
val box = Box()
box.size = 5
println(box.size) // 5
} - 注意事项:
- 自定义访问器:避免无限递归(如
get() = size
)。 - 初始化:必须初始化或延迟。
- 自定义访问器:避免无限递归(如
6.4
访问控制:public
, private
,
protected
, internal
- 语法说明:
public
:默认,公开。private
:类内可见。protected
:类及子类可见。internal
:模块内可见。
- 应用场景:
- 封装性控制。
- 底层原理:
- 编译为 JVM 访问修饰符。
- 示例代码:
1
2
3
4
5class Example {
private val secret = 42
protected val subclassVisible = "Protected"
internal val moduleVisible = "Internal"
} - 注意事项:
internal
:模块定义需明确。- 过度限制:影响扩展性。
6.5 继承:open
, :
- 语法说明:
open
允许继承,:
表示继承关系。
- 应用场景:
- 类层次设计。
- 底层原理:
- 编译为 JVM 继承结构。
- 示例代码:
1
2open class Animal(val name: String)
class Dog(name: String) : Animal(name) - 注意事项:
open
必要性:类默认不可继承。- 单一继承:Kotlin 不支持多重继承。
6.6 接口:interface
- 语法说明:
- 定义方法和属性,使用
override
实现。
- 定义方法和属性,使用
- 应用场景:
- 多态、行为契约。
- 底层原理:
- 编译为 JVM 接口。
- 示例代码:
1
2
3
4
5
6interface Flyable {
fun fly()
}
class Bird : Flyable {
override fun fly() = println("Flying")
} - 注意事项:
- 实现冲突:多接口需处理方法冲突。
- 默认实现:避免过度依赖。
6.7 抽象类:abstract
- 语法说明:
- 使用
abstract
定义抽象成员。
- 使用
- 应用场景:
- 提供部分实现。
- 底层原理:
- 编译为抽象类。
- 示例代码:
1
2
3
4
5
6abstract class Shape {
abstract fun area(): Double
}
class Circle(val radius: Double) : Shape() {
override fun area() = Math.PI * radius * radius
} - 注意事项:
- 抽象成员:必须被子类实现。
- 实例化:不可直接实例化。
6.8 数据类:data
- 语法说明:
- 使用
data
自动生成toString()
,equals()
,copy()
等。
- 使用
- 应用场景:
- DTO、简单数据容器。
- 底层原理:
- 编译器生成额外方法。
- 示例代码:
1
2
3
4
5data class User(val id: Int, val name: String)
fun main() {
val user = User(1, "Alice")
println(user.copy(name = "Bob")) // User(id=1, name=Bob)
} - 注意事项:
- 主构造函数:至少一个参数。
- 继承限制:不可被
open
。
6.9 对象声明:object
- 语法说明:
- 使用
object
创建单例。
- 使用
- 应用场景:
- 单例模式、工具类。
- 底层原理:
- 编译为静态实例。
- 示例代码:
1
2
3
4
5
6object Singleton {
fun hello() = println("Hello")
}
fun main() {
Singleton.hello() // Hello
} - 注意事项:
- 状态管理:单例需注意线程安全。
- 滥用:不适合频繁创建的对象。
6.10
伴生对象:companion object
- 语法说明:
- 在类中使用
companion object
定义静态成员。
- 在类中使用
- 应用场景:
- 工厂方法、静态工具。
- 底层原理:
- 编译为类的静态字段。
- 示例代码:
1
2
3
4
5
6
7
8class MyClass {
companion object {
fun create() = MyClass()
}
}
fun main() {
val instance = MyClass.create()
} - 注意事项:
- 命名:可命名以提高可读性。
- 访问:外部需通过类名访问。
7. 包与导入
7.1 包定义:package
- 语法说明:
- 使用
package
定义命名空间。
- 使用
- 应用场景:
- 代码组织、避免命名冲突。
- 底层原理:
- 编译为 JVM 包结构。
- 示例代码:
1
2
3
4
5package com.example
fun hello() = println("Hello")
fun main() {
hello() // Hello
} - 注意事项:
- 一致性:包名应与目录结构一致。
- 冲突:避免与其他包名冲突。
7.2 导入:import
- 语法说明:
- 使用
import
引入类或函数,支持别名(as
)。
- 使用
- 应用场景:
- 使用外部库、简化代码。
- 底层原理:
- 编译时解析导入路径。
- 示例代码:
1
2
3
4import kotlin.math.PI as MathPI
fun main() {
println(MathPI) // 3.141592653589793
} - 注意事项:
- 命名冲突:使用
as
解决。 - 冗余导入:IDE 可优化。
- 命名冲突:使用
8. 异常处理
8.1 try
, catch
,
finally
- 语法说明:
try
定义可能抛异常的代码,catch
处理异常,finally
确保执行。- 可作为表达式。
- 应用场景:
- 错误处理、资源清理。
- 底层原理:
- 编译为 JVM 的异常表。
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12fun main() {
val result = try {
val x = 1 / 0
"Success"
} catch (e: ArithmeticException) {
println("Error: ${e.message}")
"Failed"
} finally {
println("Cleanup")
}
println("Result: $result") // Failed
} - 注意事项:
- 异常类型:捕获具体异常,避免用
Exception
。 finally
执行:总是执行,注意资源释放。
- 异常类型:捕获具体异常,避免用
8.2 throw
- 语法说明:
- 使用
throw
抛出异常对象。
- 使用
- 应用场景:
- 自定义错误条件。
- 底层原理:
- 映射到 JVM 的
athrow
指令。
- 映射到 JVM 的
- 示例代码:
1
2
3
4
5
6
7
8
9
10fun validate(x: Int) {
if (x < 0) throw IllegalArgumentException("Negative not allowed")
}
fun main() {
try {
validate(-1)
} catch (e: IllegalArgumentException) {
println(e.message) // Negative not allowed
}
} - 注意事项:
- 异常信息:提供清晰描述。
- 滥用:不应用作流程控制。
9. 泛型
9.1 泛型类:<T>
- 语法说明:
- 使用
<T>
定义类型参数。
- 使用
- 应用场景:
- 类型安全的容器。
- 底层原理:
- 编译为 JVM 的泛型擦除,使用
Object
并插入类型检查。
- 编译为 JVM 的泛型擦除,使用
- 示例代码:
1
2
3
4
5
6class Box<T>(val value: T)
fun main() {
val intBox = Box(42)
val strBox = Box("Kotlin")
println("${intBox.value}, ${strBox.value}")
} - 注意事项:
- 类型约束:可用
where
限制。 - 运行时:无法直接获取
T
类型。
- 类型约束:可用
9.2 泛型函数
- 语法说明:
- 在函数名前加
<T>
。
- 在函数名前加
- 应用场景:
- 通用算法。
- 底层原理:
- 同泛型类,类型擦除。
- 示例代码:
1
2
3
4
5fun <T> printItem(item: T) = println(item)
fun main() {
printItem(42) // 42
printItem("Kotlin") // Kotlin
} - 注意事项:
- 类型推断:复杂场景需显式指定类型。
- 性能:避免过度泛化。
9.3 协变:out
- 语法说明:
- 使用
out
限制类型只能作为返回值。
- 使用
- 应用场景:
- 生产者模式。
- 底层原理:
- 编译器确保类型安全。
- 示例代码:
1
2
3
4
5
6
7
8
9
10interface Producer<out T> {
fun produce(): T
}
class StringProducer : Producer<String> {
override fun produce() = "Hello"
}
fun main() {
val producer: Producer<Any> = StringProducer()
println(producer.produce())
} - 注意事项:
- 限制:不能用作输入参数。
- 理解:需掌握协变概念。
9.4 逆变:in
- 语法说明:
- 使用
in
限制类型只能作为参数。
- 使用
- 应用场景:
- 消费者模式。
- 底层原理:
- 编译器检查逆变规则。
- 示例代码:
1
2
3
4
5
6
7
8
9
10interface Consumer<in T> {
fun consume(item: T)
}
class AnyConsumer : Consumer<Any> {
override fun consume(item: Any) = println(item)
}
fun main() {
val consumer: Consumer<String> = AnyConsumer()
consumer.consume("Hello")
} - 注意事项:
- 限制:不能用作返回值。
- 复杂性:与协变配合需小心。
9.5 通配符:*
- 语法说明:
- 表示未知类型,类似 Java 的
?
。
- 表示未知类型,类似 Java 的
- 应用场景:
- 类型无关操作。
- 底层原理:
- 编译为泛型上限
Any?
。
- 编译为泛型上限
- 示例代码:
1
2
3
4fun printList(list: List<*>) = println(list)
fun main() {
printList(listOf(1, "A")) // [1, A]
} - 注意事项:
- 限制:无法访问具体类型方法。
- 替代:可用具体类型替换。
10. 空安全
10.1 可空类型:?
- 语法说明:
- 在类型后加
?
表示可为null
。
- 在类型后加
- 应用场景:
- 处理潜在的
null
值。
- 处理潜在的
- 底层原理:
- 编译器强制类型检查。
- 示例代码:
1
2
3
4fun main() {
val str: String? = null
println(str) // null
} - 注意事项:
- 过度使用:过多
?
增加空检查负担。 - 初始化:尽量推迟到确定非空。
- 过度使用:过多
10.2 安全调用:?.
- 语法说明:
- 若对象为
null
,返回null
,否则调用方法。
- 若对象为
- 应用场景:
- 避免空指针异常。
- 底层原理:
- 编译为条件跳转。
- 示例代码:
1
2
3
4fun main() {
val str: String? = null
println(str?.length) // null
} - 注意事项:
- 链式调用:多级
?.
返回类型可能是嵌套可空。 - 性能:频繁使用增加分支。
- 链式调用:多级
10.3 Elvis 操作符:?:
- 语法说明:
- 若左边为
null
,返回右边值。
- 若左边为
- 应用场景:
- 提供默认值。
- 底层原理:
- 编译为条件表达式。
- 示例代码:
1
2
3
4
5fun main() {
val str: String? = null
val length = str?.length ?: -1
println(length) // -1
} - 注意事项:
- 类型一致:左右类型需匹配。
- 副作用:右边避免复杂逻辑。
10.4 非空断言:!!
- 语法说明:
- 强制解包,若为
null
抛异常。
- 强制解包,若为
- 应用场景:
- 确信非空时使用。
- 底层原理:
- 编译为直接访问,若
null
抛NullPointerException
。
- 编译为直接访问,若
- 示例代码:
1
2
3
4fun main() {
val str: String? = "Kotlin"
println(str!!.length) // 6
} - 注意事项:
- 风险:滥用导致运行时异常。
- 替代:优先用
?.
或?:
。
11. 注解
11.1 内置注解
Kotlin 提供了一系列内置注解,主要用于控制编译器行为、与 JVM 平台交互或增强代码语义。以下是所有内置注解的完整列表,涵盖标准库中定义的注解(基于 Kotlin 1.9 及之前版本):
@Deprecated
- 语法说明:
- 标记代码元素(类、函数、属性等)为废弃状态。
- 参数:
message: String
(必填,废弃原因),replaceWith: ReplaceWith
(可选,替代方案),level: DeprecationLevel
(可选,废弃级别:WARNING
或ERROR
,默认WARNING
)。
- 应用场景:
- API 维护:提示用户停止使用旧 API。
- 代码迁移:引导开发者转向新实现。
- 底层原理:
- 编译器在编译时发出警告或错误(取决于
level
),并在生成的 JVM 字节码中添加@java.lang.Deprecated
。
- 编译器在编译时发出警告或错误(取决于
- 示例代码:
1
2
3
4
5
6
7
fun oldFunc() = println("Old")
fun newFunc() = println("New")
fun main() {
oldFunc() // 编译器警告:'oldFunc' is deprecated
newFunc() // New
} - 注意事项:
- 信息:
message
应清晰说明废弃原因。 - 替代方案:
ReplaceWith
提供可直接替换的代码,提升迁移效率。 - 级别:使用
ERROR
时调用处会编译失败,谨慎使用。
- 信息:
@Suppress
- 语法说明:
- 抑制特定的编译器警告或错误。
- 参数:可变字符串数组(如
"DEPRECATION"
),指定要抑制的警告类型。
- 应用场景:
- 临时忽略无关警告(如使用废弃 API)。
- 清理代码时避免过多告警干扰。
- 底层原理:
- 编译器在分析代码时跳过指定警告的检查,不影响生成的字节码。
- 示例代码:
1
2
3
4
5
6
7
fun oldFunc() = println("Old")
fun newFunc() = println("New")
fun main() {
oldFunc() // 无警告
} - 注意事项:
- 范围:尽量具体到最小作用域,避免隐藏重要问题。
- 警告类型:需查阅文档确认有效的警告名称(如
"UNUSED_VARIABLE"
)。
@JvmOverloads
- 语法说明:
- 为带有默认参数的函数或构造函数生成 JVM 重载方法。
- 无参数,直接标注在函数或构造函数上。
- 应用场景:
- 与 Java 互操作:使 Kotlin 默认参数对 Java 调用者可见。
- 简化 API:提供多种调用方式。
- 底层原理:
- 编译器为每个默认参数生成重载方法,JVM 字节码中表现为独立方法。
- 示例代码:
1
2
3
4
5
6
7
fun greet(name: String = "Guest", greeting: String = "Hello") = "$greeting, $name!"
fun main() {
println(greet()) // Hello, Guest!
println(greet("Alice")) // Hello, Alice!
println(greet("Bob", "Hi")) // Hi, Bob!
} - 注意事项:
- 参数顺序:默认参数需连续靠后,否则生成不完整。
- 性能:参数过多时增加字节码大小。
- 平台限制:仅对 JVM 有效。
@JvmStatic
- 语法说明:
- 将伴生对象中的函数或属性标记为静态,生成 JVM 静态方法或字段。
- 应用于伴生对象成员。
- 应用场景:
- 与 Java 互操作:使伴生对象成员可通过类名直接调用。
- 工具类设计:模拟 Java 静态方法。
- 底层原理:
- 编译器在类中生成静态方法,绕过伴生对象实例,直接映射到 JVM 静态调用。
- 示例代码:
1
2
3
4
5
6
7
8
9
10class Utils {
companion object {
fun sayHello() = println("Hello from static")
}
}
fun main() {
Utils.sayHello() // Kotlin 调用
// Java: Utils.sayHello();
} - 注意事项:
- 适用范围:仅限伴生对象。
- 冗余:非 Java 交互时无需使用。
@JvmField
- 语法说明:
- 将属性暴露为 JVM 的公共字段,跳过 getter/setter。
- 应用于属性声明。
- 应用场景:
- 与 Java 互操作:直接访问字段而非通过方法。
- 性能优化:避免访问器开销。
- 底层原理:
- 编译器生成 public 字段而非封装属性,移除 Kotlin 的属性封装。
- 示例代码:
1
2
3
4
5
6
7
8
9class Data {
val id = 42
}
fun main() {
val d = Data()
println(d.id) // 42
// Java: int value = new Data().id;
} - 注意事项:
- 封装性:丧失 getter/setter 控制。
- 限制:不能与
private
或自定义访问器共用。
@Throws
- 语法说明:
- 指定函数可能抛出的异常,生成 JVM 的
throws
声明。 - 参数:异常类的
KClass
列表(如@Throws(IOException::class)
)。
- 指定函数可能抛出的异常,生成 JVM 的
- 应用场景:
- 与 Java 互操作:告知 Java 调用者异常类型。
- 文档化:明确异常行为。
- 底层原理:
- 编译器在字节码中添加
throws
子句,与 Java 的异常声明一致。
- 编译器在字节码中添加
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12import java.io.IOException
fun riskyOperation() {
throw IOException("Something went wrong")
}
fun main() {
try {
riskyOperation()
} catch (e: IOException) {
println(e.message) // Something went wrong
}
} - 注意事项:
- 必要性:Kotlin 不强制异常声明,仅为 Java 兼容。
- 类型:需使用
::class
指定。
@JvmName
- 语法说明:
- 指定函数或属性在 JVM 中的名称,避免命名冲突。
- 参数:字符串,表示 JVM 名称。
- 应用场景:
- 解决签名冲突:如与 Java 方法名冲突。
- 美化 API:自定义 Java 可见名称。
- 底层原理:
- 编译器修改生成的 JVM 方法或字段名称。
- 示例代码:
1
2
3
4
5
6
fun greet() = println("Hello")
fun main() {
greet() // Hello
// Java: MyClass.customGreet();
} - 注意事项:
- 唯一性:新名称需避免冲突。
- 范围:仅影响 JVM 签名。
@JvmMultifileClass
- 语法说明:
- 将多个文件中的顶层函数合并为单个 JVM 类。
- 与
@file:JvmName
配合使用。
- 应用场景:
- 模块化开发:将分散的顶层函数整合为一个类。
- Java 互操作:统一访问入口。
- 底层原理:
- 编译器将多个文件中的函数合并到一个类文件中。
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// File1.kt
"Utils") (
fun util1() = println("Util 1")
// File2.kt
"Utils") (
fun util2() = println("Util 2")
fun main() {
util1() // Util 1
util2() // Util 2
// Java: Utils.util1(); Utils.util2();
} - 注意事项:
- 配合使用:必须与
@file:JvmName
一起使用。 - 一致性:所有文件需相同
JvmName
。
- 配合使用:必须与
@Synchronized
- 语法说明:
- 标记函数为同步,类似 Java 的
synchronized
方法。 - 应用于函数。
- 标记函数为同步,类似 Java 的
- 应用场景:
- 多线程编程:确保线程安全。
- 底层原理:
- 编译器生成 JVM 的
synchronized
块,锁定函数所属对象。
- 编译器生成 JVM 的
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12class Counter {
var count = 0
fun increment() {
count++
}
}
fun main() {
val counter = Counter()
counter.increment()
println(counter.count) // 1
} - 注意事项:
- 性能:同步降低并发性,谨慎使用。
- 范围:仅锁定当前实例。
@Volatile
- 语法说明:
- 标记属性为 volatile,确保线程间可见性。
- 应用于属性。
- 应用场景:
- 多线程编程:避免线程缓存问题。
- 底层原理:
- 映射到 JVM 的
volatile
修饰符,保证内存一致性。
- 映射到 JVM 的
- 示例代码:
1
2
3
4
5
6
7
8
9class ThreadSafe {
var flag = false
}
fun main() {
val ts = ThreadSafe()
ts.flag = true
println(ts.flag) // true
} - 注意事项:
- 限制:仅适用于
var
,不可用于局部变量。 - 开销:增加内存屏障,影响性能。
- 限制:仅适用于
@Strictfp
- 语法说明:
- 标记函数或类使用严格浮点运算,遵循 IEEE 754 标准。
- 应用于函数或类。
- 应用场景:
- 高精度浮点计算:确保跨平台一致性。
- 底层原理:
- 编译器生成 JVM 的
strictfp
修饰符,禁用浮点优化。
- 编译器生成 JVM 的
- 示例代码:
1
2
3
4
5
fun compute(x: Double): Double = x * 2.0
fun main() {
println(compute(3.14)) // 6.28
} - 注意事项:
- 使用场景:极少使用,除非明确要求一致性。
- 兼容性:仅 JVM 有效。
@PublishedApi
- 语法说明:
- 标记
internal
函数或属性为公开 API,可被内联函数间接访问。
- 标记
- 应用场景:
- 库开发:在模块内隐藏实现细节,同时允许内联函数使用。
- 底层原理:
- 编译器将
internal
元素提升为public
,但仍限制模块外直接访问。
- 编译器将
- 示例代码:
1
2
3
4
5
6
internal fun internalFunc() = "Internal"
inline fun publicFunc() = internalFunc()
fun main() {
println(publicFunc()) // Internal
} - 注意事项:
- 限制:仅与
inline
配合。 - 封装性:谨慎使用,避免泄露实现。
- 限制:仅与
@SinceKotlin
- 语法说明:
- 标记代码元素自某个 Kotlin 版本起可用。
- 参数:版本号字符串(如
"1.3"
)。
- 应用场景:
- API 文档化:提示最低支持版本。
- 底层原理:
- 仅用于元数据记录,不影响编译或运行。
- 示例代码:
1
2
3
4
5
fun modernFeature() = println("Available since 1.3")
fun main() {
modernFeature() // Available since 1.3
} - 注意事项:
- 版本检查:仅提示,不强制执行。
- 文档:建议与版本控制结合。
@OptIn
- 语法说明:
- 声明使用实验性或不稳定的 API。
- 参数:注解类的
KClass
(如@OptIn(ExperimentalTime::class)
)。
- 应用场景:
- 使用实验性特性:如协程、时间 API。
- 底层原理:
- 编译器检查是否标记,未标记时发出警告或错误。
- 示例代码:
1
2
3
4
5
6
7
8
9
10import kotlin.time.ExperimentalTime
import kotlin.time.measureTime
fun measure() {
val duration = measureTime { Thread.sleep(100) }
println(duration) // ~100ms
}
fun main() {
measure()
} - 注意事项:
- 风险:实验性 API 可能变更。
- 范围:可用于文件或模块级别。
@file:JvmName
- 语法说明:
- 指定文件编译后在 JVM 中的类名。
- 参数:字符串,表示类名。
- 应用场景:
- 顶层函数命名:避免默认的
FileKt
类名。 - 与
@JvmMultifileClass
配合。
- 顶层函数命名:避免默认的
- 底层原理:
- 编译器修改生成类的名称。
- 示例代码:
1
2
3
4
5
6"MyUtils") (
fun util() = println("Utility")
fun main() {
util() // Utility
// Java: MyUtils.util();
} - 注意事项:
- 冲突:确保名称唯一。
- 范围:仅文件级有效。
@file:Suppress
- 语法说明:
- 在文件级别抑制警告。
- 参数:警告类型字符串数组。
- 应用场景:
- 文件级警告清理。
- 底层原理:
- 同
@Suppress
,作用于整个文件。
- 同
- 示例代码:
1
2
3
4
5"UNUSED_VARIABLE") (
fun main() {
val unused = 42 // 无警告
println("Done")
} - 注意事项:
- 范围:影响整个文件,谨慎使用。
- 替代:局部
@Suppress
更精准。
完整示例整合
以下是一个综合示例,展示部分内置注解的协同使用: 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"Demo") (
fun oldApi() = println("Old API")
fun newApi(message: String = "New", count: Int = 1) = println("$message repeated $count times")
class Example {
companion object {
fun staticMethod() = println("Static")
}
var flag = false
fun syncMethod() {
flag = true
}
}
fun measureTime() {
val duration = kotlin.time.measureTime { Thread.sleep(100) }
println("Took $duration")
}
fun main() {
oldApi() // Old API (警告被抑制)
newApi() // New repeated 1 times
newApi("Hi") // Hi repeated 1 times
Example.staticMethod() // Static
measureTime() // Took ~100ms
}
11.2
自定义注解:annotation
- 语法说明:
- 使用
annotation class
定义。
- 使用
- 应用场景:
- 元编程、框架开发。
- 底层原理:
- 编译为 JVM 注解。
- 示例代码:
1
2
3
4
5
6annotation class MyAnnotation(val priority: Int)
fun annotated() = println("Annotated")
fun main() {
annotated()
} - 注意事项:
- 运行时:需加
@Retention
指定保留级别。 - 参数:仅支持基本类型和枚举。
- 运行时:需加
二、现代 Kotlin 新特性
1. Kotlin 1.0+
1.1 Lambda
表达式:{ x -> x * 2 }
- 语法说明:
- 格式:
{ params -> expression }
,简化为{ it }
(单参数)。
- 格式:
- 应用场景:
- 集合操作、事件处理。
- 底层原理:
- 编译为匿名类或内联代码(若加
inline
)。
- 编译为匿名类或内联代码(若加
- 示例代码:
1
2
3
4
5fun main() {
val list = listOf(1, 2, 3)
val doubled = list.map { x -> x * 2 }
println(doubled) // [2, 4, 6]
} - 注意事项:
- 性能:未内联时生成对象。
- 可读性:复杂逻辑不适合。
1.2 扩展函数
- 语法说明:
- 在类外定义方法,格式:
fun ReceiverType.name() { ... }
。
- 在类外定义方法,格式:
- 应用场景:
- 扩展标准库、工具函数。
- 底层原理:
- 编译为静态方法,接收者作为参数。
- 示例代码:
1
2
3
4fun String.addExclamation() = "$this!"
fun main() {
println("Hello".addExclamation()) // Hello!
} - 注意事项:
- 冲突:与类方法冲突时优先类内方法。
- 访问:不能访问私有成员。
1.3 中缀函数:infix
- 语法说明:
- 使用
infix
修饰,允许中缀调用。
- 使用
- 应用场景:
- 提高代码可读性。
- 底层原理:
- 编译为普通方法调用。
- 示例代码:
1
2
3
4infix fun Int.plus(x: Int) = this + x
fun main() {
println(5 plus 3) // 8
} - 注意事项:
- 限制:需单一参数。
- 滥用:影响代码一致性。
1.4 运算符重载:operator
- 语法说明:
- 使用
operator
定义运算符行为。
- 使用
- 应用场景:
- 自定义数学对象。
- 底层原理:
- 编译为方法调用。
- 示例代码:
1
2
3
4
5
6
7
8data 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)
} - 注意事项:
- 语义:保持运算符直观含义。
- 一致性:与标准库一致。
2. Kotlin 1.1
2.1 协程:suspend
,
launch
- 语法说明:
suspend
:标记挂起函数。launch
:启动协程。
- 应用场景:
- 异步编程、网络请求。
- 底层原理:
- 基于状态机和续体(continuation),编译器生成回调逻辑。
- 示例代码:
1
2
3
4
5
6
7
8import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World")
}
println("Hello")
} - 注意事项:
- 依赖:需引入
kotlinx-coroutines
。 - 作用域:需在协程作用域内调用。
- 依赖:需引入
3. Kotlin 1.3
3.1 内联类:inline class
- 语法说明:
- 使用
inline class
定义单值包装类。
- 使用
- 应用场景:
- 类型安全、性能优化。
- 底层原理:
- 编译时展开为原始类型。
- 示例代码:
1
2
3
4
5inline class Name(val value: String)
fun main() {
val name = Name("Kotlin")
println(name.value) // Kotlin
} - 注意事项:
- 限制:仅限单一属性。
- 兼容性:早期版本不支持。
3.2 无符号整数:UInt
,
ULong
- 语法说明:
UInt
:32 位无符号整数,ULong
:64 位,加u
或U
后缀。
- 应用场景:
- 正整数计算。
- 底层原理:
- 编译为有符号整数,运行时模拟无符号行为。
- 示例代码:
1
2
3
4
5fun main() {
val uint: UInt = 42u
val ulong: ULong = 123UL
println("$uint, $ulong")
} - 注意事项:
- 运算:需注意类型匹配。
- 范围:超出需转换。
4. Kotlin 1.4
4.1 SAM 转换改进
- 语法说明:
- 单方法接口支持 Lambda 转换。
- 应用场景:
- 简化 Java 接口调用。
- 底层原理:
- 编译为接口实现。
- 示例代码:
1
2
3
4
5
6
7fun interface Action {
fun run()
}
fun main() {
val action = Action { println("Run") }
action.run()
} - 注意事项:
- 单一方法:仅限单抽象方法。
- 明确性:避免歧义。
4.2 尾随逗号
- 语法说明:
- 参数列表、集合末尾允许逗号。
- 应用场景:
- 代码格式化。
- 底层原理:
- 语法糖,无运行时影响。
- 示例代码:
1
2
3
4val list = listOf(
1,
2,
) - 注意事项:
- 兼容性:旧版本不支持。
- 一致性:团队需统一风格。
5. Kotlin 1.5
5.1
密封接口:sealed interface
- 语法说明:
- 使用
sealed interface
限制实现类。
- 使用
- 应用场景:
- 模式匹配。
- 底层原理:
- 编译器检查实现。
- 示例代码:
1
2
3
4
5
6sealed interface Expr
data class Num(val value: Int) : Expr
fun main() {
val expr: Expr = Num(42)
println((expr as Num).value)
} - 注意事项:
- 范围:实现类需在同一模块。
- 版本:需 1.5+。
5.2 内联值类:value class
- 语法说明:
- 使用
value class
定义单值类。
- 使用
- 应用场景:
- 类型安全。
- 底层原理:
- 编译时展开。
- 示例代码:
1
2
3
4
5value class Password(val value: String)
fun main() {
val pwd = Password("secret")
println(pwd.value)
} - 注意事项:
- 限制:单一属性。
- 兼容性:需 1.5+。
6. Kotlin 1.6
6.1
挂起函数类型:suspend () -> Unit
- 语法说明:
- 定义挂起函数类型。
- 应用场景:
- 协程回调。
- 底层原理:
- 编译为续体类型。
- 示例代码:
1
2
3
4fun main() {
val suspendFunc: suspend () -> Unit = { println("Suspended") }
// 需要协程作用域调用
} - 注意事项:
- 调用:需协程作用域。
- 版本:需 1.6+。
7. Kotlin 1.8
7.1 上下文接收者:context
- 语法说明:
- 使用
context(Type)
指定接收者。
- 使用
- 应用场景:
- DSL 设计。
- 底层原理:
- 编译为隐式参数。
- 示例代码:
1
2
3
4
5context(String)
fun printWithContext() = println(this)
fun main() {
with("Hello") { printWithContext() } // Hello
} - 注意事项:
- 实验性:需启用特性。
- 复杂度:增加理解难度。
8. Kotlin 1.9+
8.1 多平台改进
- 语法说明:
- 使用
expect
和actual
定义跨平台代码。
- 使用
- 应用场景:
- 多平台开发。
- 底层原理:
- 编译器生成平台特定代码。
- 示例代码:
1
2
3
4
5
6
7
8
9expect class Platform {
fun name(): String
}
actual class Platform actual constructor() {
actual fun name() = "JVM"
}
fun main() {
println(Platform().name())
} - 注意事项:
- 配置:需多平台项目设置。
- 一致性:实现需匹配。
8.2 K2 编译器特性
- 语法说明:
- K2 是新编译器,提升性能。
- 应用场景:
- 更快编译、更严格检查。
- 底层原理:
- 重写编译流程。
- 示例代码:
- 无特定语法,仅编译器特性。
- 注意事项:
- 稳定性:仍在完善。
- 启用:需配置。
三、其他特性
1. 标准库扩展
1.1 集合:List
, Set
,
Map
- 语法说明:
listOf()
:不可变列表。setOf()
:不可变集合。mapOf()
:不可变映射。- 可变版本:
mutableListOf()
,mutableSetOf()
,mutableMapOf()
。
- 应用场景:
- 数据存储、查询。
- 底层原理:
- 基于 Java 集合类(如
ArrayList
,HashSet
,HashMap
)。
- 基于 Java 集合类(如
- 示例代码:
1
2
3
4
5
6
7
8fun main() {
val list = listOf(1, 2, 3)
val set = setOf(1, 2, 2) // [1, 2]
val map = mapOf("a" to 1, "b" to 2)
val mutableList = mutableListOf(1, 2)
mutableList.add(3)
println("$list, $set, $map, $mutableList")
} - 注意事项:
- 不可变性:
listOf()
不支持修改。 - 性能:选择合适集合类型。
- 不可变性:
1.2 字符串:String
,
StringBuilder
- 语法说明:
String
:不可变字符串。StringBuilder
:可变字符串缓冲区。
- 应用场景:
- 文本处理、动态拼接。
- 底层原理:
String
映射到java.lang.String
。StringBuilder
使用java.lang.StringBuilder
。
- 示例代码:
1
2
3
4
5fun main() {
val str = "Hello"
val sb = StringBuilder().append("Hello").append(" World")
println("$str, ${sb.toString()}")
} - 注意事项:
- 性能:大量拼接用
StringBuilder
。 - 不可变性:
String
修改生成新对象。
- 性能:大量拼接用
1.3 IO:java.io
- 语法说明:
- 使用 Java 的 IO 类(如
File
)。
- 使用 Java 的 IO 类(如
- 应用场景:
- 文件读写。
- 底层原理:
- 直接调用 Java IO 库。
- 示例代码:
1
2
3
4
5import java.io.File
fun main() {
File("test.txt").writeText("Hello")
println(File("test.txt").readText()) // Hello
} - 注意事项:
- 异常:需处理 IO 异常。
- 资源:确保关闭流。
1.4
并发:kotlin.coroutines
- 语法说明:
- 使用
kotlinx.coroutines
提供协程支持。
- 使用
- 应用场景:
- 异步任务、并发处理。
- 底层原理:
- 基于状态机和续体。
- 示例代码:
1
2
3
4
5
6
7
8import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
delay(1000L)
println("World")
}
println("Hello")
} - 注意事项:
- 依赖:需添加库。
- 取消:注意协程生命周期。
2. 反射与运行时
2.1 类引用:::class
- 语法说明:
- 获取类的
KClass
对象。
- 获取类的
- 应用场景:
- 反射、元编程。
- 底层原理:
- 返回运行时类引用。
- 示例代码:
1
2
3
4fun main() {
val ref = String::class
println(ref.simpleName) // String
} - 注意事项:
- 性能:反射开销大。
- 类型:区分
::class
和::class.java
。
2.2 函数引用:::function
- 语法说明:
- 获取函数引用。
- 应用场景:
- 函数式编程。
- 底层原理:
- 编译为函数对象。
- 示例代码:
1
2
3
4
5fun hello() = println("Hello")
fun main() {
val ref = ::hello
ref() // Hello
} - 注意事项:
- 适用性:仅限顶层或成员函数。
- 性能:避免频繁创建。
2.3
反射库:kotlin.reflect
- 语法说明:
- 使用
kotlin.reflect
访问类、属性等。
- 使用
- 应用场景:
- 动态检查。
- 底层原理:
- 基于 JVM 反射。
- 示例代码:
1
2
3
4
5
6import kotlin.reflect.full.memberProperties
data class Person(val name: String)
fun main() {
val props = Person::class.memberProperties
println(props.map { it.name }) // [name]
} - 注意事项:
- 依赖:需添加
kotlin-reflect
。 - 开销:避免在性能敏感处使用。
- 依赖:需添加
3. 委托
3.1
属性委托:by lazy
, by Delegates
- 语法说明:
- 使用
by
将属性委托给代理对象。 lazy
:延迟初始化,线程安全。Delegates.observable
:属性变化监听。
- 使用
- 应用场景:
lazy
:延迟加载资源。observable
:状态监听(如 UI 更新)。
- 底层原理:
lazy
:编译为Lazy
对象,首次访问时初始化。observable
:使用ObservableProperty
包装,调用回调。
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import 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
} - 注意事项:
lazy
线程安全:默认同步,需明确模式(如LazyThreadSafetyMode.NONE
)。observable
开销:每次赋值触发回调,注意性能。- 初始化:
lazy
不可重新赋值。
3.2 类委托:by
- 语法说明:
- 使用
by
将接口实现委托给对象。
- 使用
- 应用场景:
- 组合优于继承、代理模式。
- 底层原理:
- 编译为代理调用。
- 示例代码:
1
2
3
4
5
6
7
8
9
10
11interface Printer {
fun print()
}
class PrinterImpl : Printer {
override fun print() = println("Printing")
}
class Delegator(printer: Printer) : Printer by printer
fun main() {
val delegator = Delegator(PrinterImpl())
delegator.print() // Printing
} - 注意事项:
- 覆盖:委托后仍可重写方法。
- 依赖:确保委托对象可靠。