Kotlin 习题集 · 进阶篇
涵盖面向对象、扩展、Lambda、泛型、协程基础等核心进阶内容。
第一章 面向对象编程
1.1 类与构造器
题目: 定义一个 User 类,包含:
- 属性:
name(只读)、age(可变)、email(默认"unknown") - 主构造器直接初始化属性
- 在主构造器中添加校验:
age必须 >= 0
答案:
kotlin
class User(
val name: String,
var age: Int,
val email: String = "unknown"
) {
init {
require(age >= 0) { "Age must be non-negative" }
}
}
fun main() {
val user = User("Alice", 25)
println("${user.name}, ${user.age}, ${user.email}") // Alice, 25, unknown
user.age = 30
println(user.age) // 30
// user.name = "Bob" // 编译错误,val 不可修改
// val invalid = User("Bob", -1) // 运行时异常
}
1.2 次构造器与委托
题目: 定义 Person 类,使用主构造器初始化 name,次构造器接受 age 并委托给主构造器。
答案:
kotlin
class Person(val name: String) {
var age: Int = 0
constructor(name: String, age: Int) : this(name) {
this.age = age
}
constructor(name: String, age: Int, city: String) : this(name, age) {
println("Created: $name, $age, $city")
}
}
fun main() {
val p1 = Person("Alice")
println("${p1.name}, age=${p1.age}") // Alice, age=0
val p2 = Person("Bob", 30)
println("${p2.name}, age=${p2.age}") // Bob, age=30
Person("Carol", 25, "Beijing")
}
1.3 延迟初始化
题目: 定义一个 Database 类,使用 lateinit 延迟初始化 connection,在 connect() 方法中赋值。
答案:
kotlin
class Database {
lateinit var connection: String
fun connect() {
connection = "Connected to database"
}
fun isConnected(): Boolean {
return ::connection.isInitialized
}
}
fun main() {
val db = Database()
println(db.isConnected()) // false
db.connect()
println(db.isConnected()) // true
println(db.connection) // Connected to database
}
1.4 数据类
题目: 定义 Point 数据类,包含 x, y,实现:
- 创建两个点,使用
copy复制并修改 y - 用
componentN解构 - 测试
equals/hashCode/toString
答案:
kotlin
data class Point(val x: Int, val y: Int)
fun main() {
val p1 = Point(1, 2)
val p2 = Point(1, 2)
println(p1) // Point(x=1, y=2)
println(p1 == p2) // true
println(p1.hashCode() == p2.hashCode()) // true
// copy 并修改
val p3 = p1.copy(y = 10)
println(p3) // Point(x=1, y=10)
// 解构
val (a, b) = p1
println("a=$a, b=$b") // a=1, b=2
// 用于集合
val points = listOf(Point(1,2), Point(3,4))
println(points.toString()) // [Point(x=1, y=2), Point(x=3, y=4)]
}
1.5 枚举类
题目: 定义 Color 枚举(RED, GREEN, BLUE),添加 rgb 属性返回颜色对应的 RGB 值。实现根据名称查找颜色。
答案:
kotlin
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF);
fun hex() = "#%06X".format(rgb)
}
fun main() {
println(Color.RED.rgb) // 16711680
println(Color.GREEN.hex()) // #00FF00
// 遍历
Color.values().forEach {
println("${it.name} = ${it.hex()}")
}
// 通过名称查找
val color = Color.valueOf("BLUE")
println(color) // BLUE
// 与 when 配合(穷举检查)
fun getColorName(c: Color) = when (c) {
Color.RED -> "红色"
Color.GREEN -> "绿色"
Color.BLUE -> "蓝色"
}
println(getColorName(Color.RED)) // 红色
}
1.6 嵌套类与内部类
题目: 定义 Outer 类包含嵌套类 Nested 和内部类 Inner,说明它们的区别。
答案:
kotlin
class Outer {
val outerVal = "outer"
class Nested {
// 嵌套类不能访问外部类的成员
fun greet() = "Hello from Nested"
}
inner class Inner {
// 内部类可以访问外部类的成员
fun greet() = "Hello from Inner, outerVal=$outerVal"
}
}
fun main() {
// 嵌套类直接通过外部类访问
println(Outer.Nested().greet()) // Hello from Nested
// 内部类需要外部类实例
val outer = Outer()
println(outer.Inner().greet()) // Hello from Inner, outerVal=outer
}
1.7 对象表达式与 object 声明
题目: 使用 object 声明单例 Config,使用对象表达式实现临时接口。
答案:
kotlin
// 单例对象
object Config {
val host = "localhost"
val port = 8080
fun info() = "Config: $host:$port"
}
fun main() {
println(Config.info()) // Config: localhost:8080
// 对象表达式:临时实现接口
val listener = object : Runnable {
override fun run() {
println("Running!")
}
}
listener.run() // Running!
// 带状态的对象表达式
var counter = 0
val inc = object {
fun add() { counter++ }
fun get() = counter
}
inc.add()
println(inc.get()) // 1
}
1.8 伴生对象
题目: 为 Person 类添加 companion object,实现工厂方法 create 和常量 MAX_AGE。
答案:
kotlin
class Person(val name: String, val age: Int) {
companion object {
const val MAX_AGE = 150
const val MIN_AGE = 0
// 工厂方法
fun create(name: String, age: Int): Person {
return Person(name, age.coerceIn(MIN_AGE, MAX_AGE))
}
// 便捷工厂
fun createAdult(name: String) = Person(name, 18)
// 可以实现接口
interface Factory {
fun create(): Person
}
}
}
fun main() {
val p = Person.create("Alice", 200)
println("${p.name}, ${p.age}") // Alice, 150 (被限制)
val adult = Person.createAdult("Bob")
println("${adult.name}, ${adult.age}") // Bob, 18
// 通过类名直接访问伴生对象成员
println(Person.MAX_AGE) // 150
}
第二章 继承与接口
2.1 抽象类
题目: 定义抽象类 Shape,包含抽象属性 area 和抽象方法 draw()。实现 Circle 和 Rectangle 子类。
答案:
kotlin
abstract class Shape {
abstract val area: Double
abstract fun draw(): String
// 抽象类可以有非抽象方法
fun description() = "Shape with area: $area"
}
class Circle(val radius: Double) : Shape() {
override val area: Double get() = Math.PI * radius * radius
override fun draw() = "Circle(radius=$radius)"
}
class Rectangle(val width: Double, val height: Double) : Shape() {
override val area: Double get() = width * height
override fun draw() = "Rectangle(${width}x${height})"
}
fun main() {
val shapes = listOf(Circle(5.0), Rectangle(4.0, 6.0))
shapes.forEach {
println("${it.draw()}, area=${"%.2f".format(it.area)}")
// Circle(radius=5.0), area=78.54
// Rectangle(4.0x6.0), area=24.00
}
}
2.2 接口
题目: 定义接口 Flyable 和 Swimmable,实现 Duck 类同时实现两个接口。
答案:
kotlin
interface Flyable {
fun fly(): String
val maxAltitude: Int get() = 1000 // 接口可以有默认属性
}
interface Swimmable {
fun swim(): String
}
class Duck(val name: String) : Flyable, Swimmable {
override fun fly() = "$name is flying at alt ${maxAltitude}m"
override fun swim() = "$name is swimming"
// 实现多个接口时,如果方法冲突必须明确覆盖
fun show() {
println(fly())
println(swim())
}
}
fun main() {
val duck = Duck("Donald")
duck.show()
// 接口引用
val f: Flyable = duck
println(f.fly()) // Donald is flying at alt 1000m
val s: Swimmable = duck
println(s.swim()) // Donald is swimming
}
2.3 接口与抽象类的选择
题目: 说明以下场景应选择接口还是抽象类:
Printable让Document和Image实现打印Vehicle有Engine和Wheel作为组成部分Comparable让不同类型实现比较
答案:
kotlin
// 场景1 & 3: 接口更适合(行为契约,无状态)
interface Printable {
fun print()
}
interface Comparable<T> {
fun compareTo(other: T): Int
}
// 场景2: 组合优于继承,但抽象类可用于"是"关系
// 如果所有 Vehicle 都有引擎和轮子,可用抽象类
abstract class Vehicle {
abstract val engine: String
abstract val wheelCount: Int
}
class Car : Vehicle() {
override val engine = "V8"
override val wheelCount = 4
}
// 关键区别:
// - 接口:无状态,多实现,Java 8+ 支持 default 方法
// - 抽象类:有状态,单继承,适合"is-a"关系
// 示例:Comparable 接口
data class Person(val name: String, val age: Int) : Comparable<Person> {
override fun compareTo(other: Person) = age - other.age
}
fun main() {
println(Person("Alice", 30) > Person("Bob", 25)) // true
}
2.4 方法覆盖规则
题目: 定义父类 Base 有方法 foo(),子类 Derived 覆盖它。使用 super 调用父类实现。
答案:
kotlin
open class Base {
open fun foo() = "Base.foo()"
fun bar() = "Base.bar()"
}
class Derived : Base() {
override fun foo() = "Derived.foo()"
fun callSuper() = super.foo()
}
fun main() {
val d = Derived()
println(d.foo()) // Derived.foo()
println(d.callSuper()) // Base.foo()
println(d.bar()) // Base.bar()
// 多态
val b: Base = Derived()
println(b.foo()) // Derived.foo() (运行时多态)
println(b.bar()) // Base.bar()
}
第三章 扩展与高阶函数
3.1 扩展函数
题目: 为 String 类添加扩展函数 addExclamation,将感叹号添加到字符串末尾;添加扩展属性 lastChar。
答案:
kotlin
fun String.addExclamation(): String = this + "!"
// 扩展属性
val String.lastChar: Char
get() = this[length - 1]
fun main() {
println("Hello".addExclamation()) // Hello!
println("Kotlin".lastChar) // n
// 可空 receiver
fun String?.orEmpty(): String = this ?: ""
val nullStr: String? = null
println(nullStr.orEmpty()) // (空字符串)
}
3.2 扩展函数实战
题目: 为 List<Int> 添加扩展函数:
sumOfDigits()- 返回所有数字(假设元素是多位整数)的位数总和average()- 自定义平均值(实现与标准库相同功能)
答案:
kotlin
fun List<Int>.sumOfDigits(): Int {
return this.sumOf { kotlin.math.abs(it).toString().length }
}
// 例如 [12, 3, 456] -> 位数: 2 + 1 + 3 = 6
fun List<Int>.customAverage(): Double {
return if (isEmpty()) 0.0 else sum().toDouble() / size
}
fun main() {
println(listOf(12, 3, 456).sumOfDigits()) // 6
println(listOf(1, 2, 3, 4).customAverage()) // 2.5
// 链式调用
println(listOf(10, 20, 30).map { it * 2 }.customAverage()) // 40.0
}
3.3 Lambda 表达式基础
题目: 将以下匿名函数转换为 Lambda 表达式:
kotlin
val add = fun(x: Int, y: Int): Int = x + y
val square = fun(x: Int): Int = x * x
答案:
kotlin
// Lambda 表达式语法
val add: (Int, Int) -> Int = { x, y -> x + y }
val square: (Int) -> Int = { it * it } // 单参数可用 it
fun main() {
println(add(3, 4)) // 7
println(square(5)) // 25
// 高阶函数中使用 Lambda
val list = listOf(1, 2, 3, 4, 5)
// 完整语法
list.forEach({ x: Int -> println(x) })
// 最后参数可移到括号外
list.forEach { x -> println(x) }
// 单参数可用 it
list.forEach { println(it) }
// 多参数 Lambda
val map = mapOf("a" to 1, "b" to 2)
map.forEach { (k, v) -> println("$k -> $v") }
}
3.4 高阶函数
题目: 定义高阶函数 applyIf,接受值和条件函数,仅当条件为真时执行转换函数。
答案:
kotlin
fun <T, R> T.applyIf(predicate: (T) -> Boolean, transform: (T) -> R): R? {
return if (predicate(this)) transform(this) else null
}
fun main() {
val result1 = 10.applyIf({ it > 5 }, { it * 2 })
println(result1) // 20
val result2 = 3.applyIf({ it > 5 }, { it * 2 })
println(result2) // null
// 字符串示例
val s = "Kotlin"
val upper = s.applyIf({ it.length > 3 }, { it.uppercase() })
println(upper) // KOTLIN
// 结合 let
val nullable: String? = null
val processed = nullable?.applyIf({ it.length > 3 }, { it.uppercase() })
println(processed) // null
}
3.5 inline 函数
题目: 解释为什么 repeat 是内联函数,定义一个简化版 myRepeat。
答案:
kotlin
// 内联函数:编译器将函数调用替换为函数体,避免 Lambda 带来的开销
inline fun myRepeat(times: Int, action: () -> Unit) {
for (i in 0 until times) {
action()
}
}
// noinline: 不内联 Lambda 参数
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
println("Calling inlined:")
inlined()
println("Calling not inlined:")
notInlined()
}
// crossinline: 确保 Lambda 不允许非局部返回
inline fun bar(crossinline action: () -> Unit) {
println("Before")
action() // 不能使用 return
println("After")
}
fun main() {
myRepeat(3) {
println("Hello") // 打印3次
}
// 内联的代价:代码膨胀,但性能更好(尤其在循环中)
}
第四章 泛型
4.1 泛型类与函数
题目: 定义泛型 Box<T> 类,存储单一值;定义泛型函数 swap,交换数组中两个位置的元素。
答案:
kotlin
class Box<T>(var content: T) {
override fun toString() = "Box($content)"
}
fun <T> swap(arr: Array<T>, i: Int, j: Int) {
val temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
fun main() {
val box = Box("Hello")
println(box) // Box(Hello)
box.content = "World"
println(box) // Box(World)
val arr = arrayOf(1, 2, 3, 4)
swap(arr, 0, 3)
println(arr.toList()) // [4, 2, 3, 1]
// 类型约束
fun <T : Comparable<T>> maxOf(a: T, b: T): T = if (a > b) a else b
println(maxOf(5, 3)) // 5
println(maxOf("apple", "banana")) // banana
}
4.2 泛型约束
题目: 定义函数 sumOfList,约束 T 必须为 Number 子类,返回元素总和。
答案:
kotlin
fun <T : Number> sumOfList(list: List<T>): Double {
return list.sumOf { it.toDouble() }
}
fun main() {
println(sumOfList(listOf(1, 2, 3))) // 6.0
println(sumOfList(listOf(1.5, 2.5, 3.5))) // 7.5
println(sumOfList(listOf(1, 2.5, 3))) // 6.5
// 多个约束
fun <T> saveToCache(item: T) where T : Any, T : Comparable<T> {
println("Saving $item")
}
saveToCache("Hello")
// saveToCache(null) // 编译错误,约束 T : Any 排除 null
}
4.3 协变与逆变
题目: 解释 out(协变)和 in(逆变)的使用场景,定义 Producer<out T> 和 Consumer<in T>。
答案:
kotlin
// 协变:T 只出现在输出位置(生产)
interface Producer<out T> {
fun produce(): T
// fun consume(item: T) // 编译错误,不能在输入位置使用 T
}
// 逆变:T 只出现在输入位置(消费)
interface Consumer<in T> {
fun consume(item: T)
// fun produce(): T // 编译错误,不能在输出位置使用 T
}
// 不变:两者皆有
interface Container<T> {
fun get(): T
fun put(item: T)
}
class Food
class Apple : Food()
class FoodProducer : Producer<Food> {
override fun produce() = Food()
}
class AppleProducer : Producer<Apple> {
override fun produce() = Apple()
}
fun main() {
// Producer<Apple> 可赋值给 Producer<Food>(协变)
val producer: Producer<Food> = AppleProducer()
println(producer.produce())
// Consumer<Food> 可赋值给 Consumer<Apple>(逆变)
val consumer: Consumer<Apple> = FoodProducer()
consumer.consume(Apple())
}
4.4 泛型擦除与 reified
题目: 说明类型擦除的影响,定义 reified 内联函数实现在运行时获取泛型类型。
答案:
kotlin
// 类型擦除:运行时不保留泛型信息
class Container<T> {
// 在运行时会变成 Object
}
fun <T> printType Erasure() {
// println(T::class) // 编译错误,擦除后无法获取
}
// reified:内联函数保留泛型类型信息
inline fun <reified T> printType() {
println(T::class.simpleName)
}
inline fun <reified T> isInstanceOf(value: Any): Boolean {
return value is T
}
fun main() {
printType<String>() // String
printType<Int>() // Int
println(isInstanceOf<String>("hello")) // true
println(isInstanceOf<String>(123)) // false
// 应用:创建实例
inline fun <reified T> create(): T = T::class.java.getDeclaredConstructor().newInstance() as T
}
第五章 协程基础
5.1 协程构建器
题目: 使用 launch、async、runBlocking 创建协程,说明它们的区别。
答案:
kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
// launch: 异步执行,不返回结果,fire-and-forget
val job = launch {
delay(100)
println("Launch done")
}
// async: 返回结果,Deferred<T>
val deferred = async {
delay(200)
42
}
println("Result: ${deferred.await()}") // 等待并获取结果
job.join() // 等待 launch 完成
println("All done")
}
// 区别:
// - launch: 不返回结果,用于"执行并忘记"任务
// - async: 返回 Deferred,适合并行执行并收集结果
// - runBlocking: 阻塞当前线程直到协程完成(仅用于 main 或测试)
5.2 挂起函数
题目: 定义挂起函数 fetchUser 和 fetchOrders,并行获取后组合输出。
答案:
kotlin
import kotlinx.coroutines.*
suspend fun fetchUser(): String {
delay(100) // 模拟网络延迟
return "Alice"
}
suspend fun fetchOrders(): List<String> {
delay(150)
return listOf("Order1", "Order2", "Order3")
}
fun main() = runBlocking {
// 顺序执行
val start = System.currentTimeMillis()
val user = fetchUser()
val orders = fetchOrders()
println("Sequential: ${System.currentTimeMillis() - start}ms") // ~250ms
// 并行执行
val start2 = System.currentTimeMillis()
val userDeferred = async { fetchUser() }
val ordersDeferred = async { fetchOrders() }
println("User: ${userDeferred.await()}")
println("Orders: ${ordersDeferred.await()}")
println("Parallel: ${System.currentTimeMillis() - start2}ms") // ~150ms
}
5.3 协程上下文与调度器
题目: 使用不同调度器运行协程:
Dispatchers.Default- CPU 密集型Dispatchers.IO- IO 密集型Dispatchers.Main- UI 线程(Android)
答案:
kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
// CPU 密集型:默认调度器(共享线程池,核心数)
launch(Dispatchers.Default) {
println("Default: ${Thread.currentThread().name}")
}
// IO 密集型:IO 调度器(大量线程)
launch(Dispatchers.IO) {
println("IO: ${Thread.currentThread().name}")
}
// 单线程调度器:确保顺序执行
val single = Dispatchers.newSingleThreadContext("my-thread")
launch(single) {
println("Single: ${Thread.currentThread().name}")
}.join()
// 切换上下文
launch(Dispatchers.Default) {
println("Before: ${Thread.currentThread().name}")
withContext(Dispatchers.IO) {
println("Switched: ${Thread.currentThread().name}")
}
println("Back: ${Thread.currentThread().name}")
}
}
5.4 结构化并发
题目: 使用 coroutineScope 和 supervisorScope 实现结构化并发,理解作用域取消。
答案:
kotlin
import kotlinx.coroutines.*
fun main() = runBlocking {
// coroutineScope: 子协程失败会导致整个作用域取消
try {
coroutineScope {
launch {
delay(100)
println("Task 1 done")
}
launch {
delay(50)
throw RuntimeException("Task 2 failed!")
}
}
} catch (e: Exception) {
println("Scope cancelled: ${e.message}") // Task 2 failed!
}
// supervisorScope: 子协程失败不会影响兄弟协程
supervisorScope {
launch {
delay(100)
println("Task A done") // 仍会执行
}
launch {
delay(50)
throw RuntimeException("Task B failed!")
}
}
println("Supervisor scope survived")
// 取消
val job = launch {
repeat(1000) { i ->
println("Task $i")
delay(100)
}
}
delay(350)
println("Cancelling...")
job.cancel()
job.join()
println("Cancelled")
}
5.5 Flow 基础
题目: 使用 flow 创建数据流,实现冷流、背压和取消。
答案:
kotlin
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun numbersFlow(): Flow<Int> = flow {
for (i in 1..5) {
delay(100)
emit(i)
}
}
fun main() = runBlocking {
// 冷流:只有 collect 时才会执行
val flow = numbersFlow()
launch {
flow.collect { println("Collector1: $it") }
}
delay(50)
// 背压:使用 buffer / collect
launch {
numbersFlow()
.buffer() // 缓冲,避免发射阻塞
.collect {
delay(150) // 处理慢于发射
println("Slow collector: $it")
}
}
// 取消
withTimeoutOrNull(350) {
numbersFlow().collect { println("Timeout: $it") }
}
// 转换操作
numbersFlow()
.map { it * it }
.filter { it > 4 }
.onEach { println("Before: $it") }
.launchIn(this) // 在协程外启动收集
delay(500)
}
第六章 操作符重载
6.1 一元与二元操作符
题目: 为自定义类 Point 重载 +、-、unaryMinus、++ 操作符。
答案:
kotlin
data class Point(val x: Int, val y: Int) {
operator fun plus(other: Point) = Point(x + other.x, y + other.y)
operator fun minus(other: Point) = Point(x - other.x, y - other.y)
unaryMinus operator fun unaryMinus() = Point(-x, -y)
operator fun inc() = Point(x + 1, y + 1)
}
fun main() {
val p1 = Point(1, 2)
val p2 = Point(3, 4)
println(p1 + p2) // Point(x=4, y=6)
println(p1 - p2) // Point(x=-2, y=-2)
println(-p1) // Point(x=-1, y=-2)
var p = Point(1, 1)
println(p++) // Point(x=1, y=1) (先返回,后++)
println(p) // Point(x=2, y=2)
}
6.2 比较与包含操作符
题目: 为 Date 类实现 compareTo,并重载 in 操作符判断日期是否在范围内。
答案:
kotlin
data class Date(val year: Int, val month: Int, val day: Int) : Comparable<Date> {
override fun compareTo(other: Date): Int {
return when {
year != other.year -> year - other.year
month != other.month -> month - other.month
else -> day - other.day
}
}
operator fun rangeTo(other: Date) = DateRange(this, other)
}
class DateRange(val start: Date, val end: Date) {
operator fun contains(date: Date): Boolean {
return date >= start && date <= end
}
}
fun main() {
val d1 = Date(2024, 1, 1)
val d2 = Date(2024, 12, 31)
val check = Date(2024, 6, 15)
println(d1 < d2) // true
println(check in d1..d2) // true
// 也可用于 when 表达式
when (check.month) {
in 1..3 -> println("Q1")
in 4..6 -> println("Q2")
else -> println("Other")
}
}
6.3 下标与调用操作符
题目: 为 Matrix 类实现 [] 下标访问和 () 调用操作符。
答案:
kotlin
class Matrix(private val data: Array<IntArray>) {
val rows = data.size
val cols = data[0].size
operator fun get(row: Int, col: Int): Int = data[row][col]
operator fun set(row: Int, col: Int, value: Int) {
data[row][col] = value
}
// 调用操作符
operator fun invoke(): String {
return buildString {
data.forEach { row ->
appendLine(row.joinToString(" "))
}
}
}
operator fun invoke(row: Int): IntArray = data[row]
}
fun main() {
val m = Matrix(arrayOf(intArrayOf(1, 2, 3), intArrayOf(4, 5, 6)))
println(m[0, 1]) // 2
m[0, 1] = 10
println(m[0, 1]) // 10
println(m()) // 打印矩阵
println(m(1).toList()) // [4, 5, 6](调用第二行)
}
答案汇总索引
| 章节 | 题目 | 核心知识点 |
|---|---|---|
| 1.1-1.8 | 类与构造器 | 主/次构造器、lateinit、数据类、枚举、嵌套类、伴生对象 |
| 2.1-2.4 | 继承与接口 | 抽象类、接口、覆盖规则 |
| 3.1-3.5 | 扩展与高阶 | 扩展函数/属性、Lambda、inline |
| 4.1-4.4 | 泛型 | 泛型类/函数、约束、协变逆变、reified |
| 5.1-5.5 | 协程 | launch/async、挂起函数、调度器、结构化并发、Flow |
| 6.1-6.3 | 操作符重载 | 一元/二元操作符、比较操作符、下标操作符 |
进阶篇结束。准备好进入 高级篇 了吗?