当前位置: 首页 > news >正文

面试复习题-kotlin

一、基础语法与特性

1. val 和 var 的区别?
  • val:声明不可变变量(只读),类似 Java 的 final
  • var:声明可变变量。
  • 推荐优先使用 val,提高代码安全性。
2. lateinit 和 by lazy 的区别?
特性lateinitby lazy
类型只能用于 var,且不能是基本类型只能用于 val
初始化手动赋值(延迟到运行时)第一次访问时初始化
线程安全否(需手动保证)是(默认 LazyThreadSafetyMode.SYNCHRONIZED
使用场景依赖注入、Android onCreate() 中初始化单例、耗时对象初始化

kotlin

深色版本

class MyClass {lateinit var name: String // 必须在使用前初始化val data by lazy { expensiveOperation() } // 第一次访问时计算
}
3. == 和 === 的区别?
  • ==结构相等(调用 equals())。
  • ===引用相等(内存地址相同)。
  • 对于基本类型,=== 会进行值比较(装箱优化)。
4. data class 有什么作用?自动生成哪些方法?
  • 用于数据载体类,自动提供:
    • equals() / hashCode()
    • toString()(格式:User(name=John, age=30)
    • copy()(复制并可修改部分属性)
    • componentN()(解构支持)
  • 要求主构造函数至少有一个参数。

kotlin

深色版本

data class User(val name: String, val age: Int)
5. sealed class(密封类)的作用?
  • 表示受限的类继承结构,所有子类必须在同一个文件中定义。
  • 在 when 表达式中可以穷尽检查,无需 else 分支。

kotlin

深色版本

sealed class Result {data class Success(val data: String) : Result()data class Error(val exception: Exception) : Result()
}fun handle(result: Result) = when(result) {is Success -> println(result.data)is Error -> println(result.exception)// 不需要 else,编译器知道已覆盖所有情况
}

二、空安全(Null Safety)

6. Kotlin 如何解决空指针异常(NPE)?
  • 类型系统区分可空类型String?)和非空类型String)。
  • 非空类型不能赋值为 null
  • 可空类型必须进行空检查才能使用。
7. 安全调用(?.)、Elvis 操作符(?:)、非空断言(!!)的区别?

kotlin

深色版本

val name: String? = getName()// 安全调用:如果 name 不为 null,调用 toUpperCase()
val upper = name?.toUpperCase()// Elvis 操作符:提供默认值
val result = name ?: "Unknown"// 非空断言:强制认为不为 null,可能抛出 NPE
val mustHave = name!!.length
8. 如何安全地进行类型转换?
  • 使用 as?(安全转换):

kotlin

深色版本

val str: String? = obj as? String

三、函数与高阶函数

9. 什么是高阶函数?举例说明。
  • 函数可以作为参数返回值

kotlin

深色版本

fun operate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {return operation(a, b)
}val result = operate(2, 3) { x, y -> x + y }
10. inline 函数的作用?
  • 内联:编译时将函数体插入调用处,避免创建匿名类和对象(提升性能)。
  • 常用于高阶函数(如 letapplyrun)。
  • 使用 noinline 可阻止部分参数内联,crossinline 限制 return
11. 常用作用域函数(letrunwithapplyalso)的区别?
函数上下文对象返回值适用场景
letitLambda 结果空安全调用、局部变量
runthisLambda 结果多个操作、初始化
withthisLambda 结果调用对象多个方法
applythis对象自身对象配置(Builder 模式)
alsoit对象自身副作用(如日志)

kotlin

深色版本

val user = User().apply { name = "John"; age = 30 } // 配置.also { println("Created: $it") }  // 副作用

四、协程(Coroutines)

12. 什么是协程?与线程的区别?
  • 协程:轻量级线程,由用户态调度,挂起不阻塞线程
  • 线程:操作系统调度,阻塞会占用线程资源。
  • 协程开销小,可创建成千上万个。
13. launch 和 async 的区别?
  • launch:启动协程,返回 Job,用于不返回结果的场景。
  • async:启动协程,返回 Deferred<T>,用于需要返回结果的场景,需调用 .await()

kotlin

深色版本

// launch:只关心执行
scope.launch { fetchData() }// async:需要结果
val deferred = scope.async { fetchData() }
val result = deferred.await()
14. 协程的上下文(CoroutineContext)包含哪些元素?
  • Job:协程的生命周期。
  • Dispatcher:指定运行线程(如 Dispatchers.IOMain)。
  • CoroutineExceptionHandler:处理未捕获异常。
  • CoroutineName:协程名称(调试用)。
15. viewModelScope 和 lifecycleScope 的作用?
  • viewModelScope:在 ViewModel 中使用,ViewModel 销毁时自动取消协程。
  • lifecycleScope:在 Activity/Fragment 中使用,生命周期结束时取消。
  • 都属于 AndroidX Lifecycle 库,避免内存泄漏。

五、面向对象与继承

16. Kotlin 类默认是 final 的,如何允许继承?
  • 使用 open 关键字:

kotlin

深色版本

open class Animal // 允许继承
class Dog : Animal() // 继承
17. object 关键字有哪些用法?
  1. 单例模式
    kotlin

    深色版本

    object NetworkManager { fun request() { ... } }
  2. 伴生对象(Companion Object)
    kotlin

    深色版本

    class MyClass {companion object { const val TAG = "MyClass" }
    }
  3. 对象表达式(匿名内部类)
    kotlin

    深色版本

    val listener = object : OnClickListener { ... }

六、集合与函数式编程

18. mapflatMapfilterreduce 的作用?

kotlin

深色版本

val list = listOf(1, 2, 3)list.map { it * 2 }        // [2, 4, 6]
list.filter { it > 1 }     // [2, 3]
list.reduce { acc, i -> acc + i } // 6val nested = listOf(listOf(1,2), listOf(3,4))
nested.flatMap { it }      // [1, 2, 3, 4] (展平)
19. MutableList 和 List 的区别?
  • List:只读接口(不能添加/删除)。
  • MutableList:可变接口。

七、与 Java 互操作

20. Kotlin 如何调用 Java 代码?有哪些注意事项?
  • 大部分无缝互操作。
  • 注意:
    • Java 的 null 在 Kotlin 中是可空类型。
    • Java 集合在 Kotlin 中可能是可变的。
    • 使用 @JvmOverloads@JvmStatic@JvmField 控制 JVM 字节码生成。
21. @JvmOverloads 的作用?
  • 让 Kotlin 函数支持默认参数,在 Java 中生成多个重载方法。

kotlin

深色版本

@JvmOverloads
fun greet(name: String = "World", age: Int = 0) { ... }

Java 中可调用:greet(), greet("John"), greet("John", 25)


八、进阶问题

22. tailrec 关键字的作用?
  • 标记尾递归函数,编译器将其优化为循环,避免栈溢出。

kotlin

深色版本

tailrec fun factorial(n: Int, acc: Int = 1): Int =if (n <= 1) acc else factorial(n - 1, n * acc)
23. 协程取消是协作式的,如何检查取消?
  • 使用 ensureActive() 或检查 isActive

kotlin

深色版本

while (isActive) {// 执行任务
}
24. Channel 和 Flow 的区别?
  • Channel冷流,生产者-消费者队列,支持挂起。
  • Flow热流,冷数据流,用于异步数据序列,支持背压。

总结

Kotlin 面试重点:

  1. 空安全?!!?:?.
  2. 协程launch/asyncscope、异常处理
  3. 函数式编程:高阶函数、let/apply 等作用域函数
  4. 语法糖data classsealed classobject
  5. Android 特有viewModelScopelifecycleScope

建议结合实际项目经验,解释这些特性如何提升代码质量、可读性和安全性

一、深入理解 Kotlin 编译与字节码

25. const val 和 val 的区别?什么情况下必须用 const
  • val:运行时赋值(可以是函数调用结果)。
  • const val编译期常量,必须是基本类型或 String,且值在编译时确定。
  • const 可用于注解、when 分支、默认参数。

kotlin

深色版本

const val TAG = "MyActivity" // ✅ 可用于注解
val version = getVersion()   // ❌ 不能用于注解@SomeAnnotation(TAG) // 只有 const val 可以
fun log(message: String = TAG) { ... } // 默认参数也需 const
26. @JvmStatic 和 @JvmField 的作用?
  • @JvmStatic:在伴生对象中,生成 静态方法(而非静态内部类的实例方法)。
  • @JvmField:将属性暴露为 public 字段,不生成 getter/setter。

kotlin

深色版本

class Utils {companion object {@JvmStatic fun doWork() { ... } // Java 中可直接 Utils.doWork()@JvmField val NAME = "Utils"   // Java 中可直接 Utils.NAME}
}
27. Kotlin 的默认参数是如何在字节码中实现的?
  • 编译器会生成多个重载方法(除非加 @JvmOverloads)。
  • 调用时,未传参的位置由编译器插入默认值。
  • 在 Java 中调用带默认参数的 Kotlin 函数,必须使用 @JvmOverloads 才能生成重载。

二、协程进阶与实战

28. 协程取消后,如何确保资源正确释放(如文件、网络连接)?
  • 使用 try { ... } finally { ... } 或 use 语句。
  • finally 块中的代码总是执行,即使协程被取消。

kotlin

深色版本

scope.launch {val file = openFile()try {while (isActive) {// 读取文件}} finally {file.close() // 即使被 cancel(),也会执行}
}
29. withContext(Dispatcher.IO) 和 launch(Dispatcher.IO) 的区别?
  • withContext挂起函数,切换上下文并返回结果,常用于函数内部。
  • launch启动新协程,不阻塞当前协程,通常用于“开火即忘”(fire and forget)。

kotlin

深色版本

// 推荐:在 suspend 函数中使用 withContext
suspend fun fetchData(): String {return withContext(Dispatcher.IO) {// 耗时操作}
}// launch 用于启动独立任务
scope.launch { fetchData() }
30. 什么是“协程泄露”(Coroutine Leak)?如何避免?
  • 定义:协程启动后未被正确取消或等待,导致资源浪费或内存泄漏。
  • 场景
    • 在 ViewModel 中启动 launch 但未绑定 viewModelScope
    • async 启动后未调用 await() 或 cancel()
  • 避免
    • 使用结构化并发(CoroutineScope)。
    • 优先使用 viewModelScope / lifecycleScope
    • 对 async 的结果必须处理。

三、泛型与类型系统

31. in 和 out 关键字的作用?(型变)
  • out T(协变):T 只作为返回值(生产者),List<Cat> 是 List<Animal> 的子类型。
  • in T(逆变):T 只作为参数(消费者),Comparator<Animal> 是 Comparator<Cat> 的子类型。

kotlin

深色版本

interface Producer<out T> {fun get(): T // T 是输出
}interface Consumer<in T> {fun consume(item: T) // T 是输入
}
32. reified 类型参数的作用?
  • 允许在内联函数中使用 T::class 或 is T,因为类型在编译时已知。

kotlin

深色版本

inline fun <reified T> getInstance(): T {return when (T::class) {String::class -> "Hello" as TInt::class -> 42 as Telse -> throw IllegalArgumentException()}
}

四、DSL(领域特定语言)

33. Kotlin 如何构建 DSL?@DslMarker 的作用?
  • 使用 lambda with receiver 和 高阶函数 构建 DSL。
  • @DslMarker 确保 DSL 的层级结构,防止跨层级调用。

kotlin

深色版本

@DslMarker
annotation class HtmlTagMarker@HtmlTagMarker
class Tag(val name: String) {fun render() = "<$name>$content</$name>"private var content = ""fun content(text: String) { content += text }
}fun tag(name: String, init: Tag.() -> Unit): Tag {val tag = Tag(name)tag.init() // 在 Tag 的上下文中执行return tag
}// 使用 DSL
val html = tag("div") {content("Hello")// 无法调用其他 Tag 的方法,因为 @DslMarker 限制了作用域
}

这是 Kotlin 构建类型安全 HTML、Gradle 脚本、Ktor 路由等的基础。


五、性能与最佳实践

34. Sequence 和 List 的操作有何不同?何时使用 Sequence
  • List 操作:立即执行,每步生成新集合(中间集合开销大)。
  • Sequence 操作:惰性求值,类似 Java Stream,只有在 toList() 或 forEach() 时才执行。

kotlin

深色版本

// List:三次遍历,生成两个中间列表
list.filter { it > 0 }.map { it * 2 }.first { it > 10 }// Sequence:一次遍历,无中间集合
sequence.filter { it > 0 }.map { it * 2 }.first { it > 10 }
  • 使用场景:大数据集、复杂链式操作、早期终止(如 first)。
35. 如何避免 Kotlin 的“过度语法糖”导致代码可读性下降?
  • 原则
    • 不滥用 apply/also 嵌套。
    • 复杂逻辑避免单行 lambda。
    • 团队统一编码规范。
    • 优先选择清晰而非“聪明”的代码。

六、Android 与 Kotlin 特有

36. by viewModels() 和 by activityViewModels() 的原理?
  • 基于 委托属性Delegates)和 ViewModelProvider
  • by 调用 getValue(),内部通过 ViewModelProvider 获取 ViewModel
  • 自动绑定生命周期。
37. Kotlin 的 when 表达式比 Java switch 强在哪里?
  • 支持任意类型(对象、字符串、枚举)。
  • 支持范围(in 1..10)、类型检查(is String)、条件(-> value > 0)。
  • 可作为表达式返回值。

kotlin

深色版本

val result = when (x) {in 1..10 -> "Small"is String -> "It's a string"else -> "Unknown"
}

七、开放性问题(考察设计能力)

38. 如何用 Kotlin 实现一个简单的依赖注入(DI)容器?
  • 使用 object 存储单例。
  • 使用高阶函数注册和获取实例。
  • 利用委托属性延迟初始化。
39. 如何设计一个线程安全的缓存(Cache)?
  • 使用 ConcurrentHashMap
  • 结合 @Volatile 和双重检查锁定(Double-Checked Locking)。
  • 或使用 synchronized 块。
40. Kotlin 多平台(KMP)的了解?
  • 一套代码,多平台共享(Android、iOS、Web、Desktop)。
  • 共享业务逻辑、网络、数据层。
  • 平台特定代码通过 expect/actual 声明。

总结:Kotlin 面试准备策略

层次考察点准备建议
基础val/var、空安全、函数熟练语法,能手写
核心协程、作用域函数、集合理解原理,能解释区别
进阶泛型、DSL、字节码了解编译机制,有实战经验
实战内存泄漏、性能优化、架构结合项目讲清楚“为什么”

最后建议

  • 准备 1-2 个 Kotlin 特性优化项目代码 的例子(如用 sealed class 替代枚举,用协程替代回调)。
  • 了解 Kotlin 1.9+ 的新特性(如 K2 编译器、required 关键字等)。

Kotlin 不仅是语法糖,更是一种设计哲学。面试官希望看到你如何用 Kotlin 写出更安全、更简洁、更易维护的代码

http://www.dtcms.com/a/365549.html

相关文章:

  • Springboot 练手项目(删除部门-接口开发)
  • Get the pikachu靶场SSRF漏洞 (windows环境)
  • AR技术赋能电力巡检:开启智能安全新时代
  • 前端-安装VueCLI
  • Ubuntu环境下的 RabbitMQ 安装与配置详细教程
  • 【开题答辩全过程】以 基于大数据的地震数据分析系统的设计与实现为例,包含答辩的问题和答案
  • 理解用户需求的方法
  • JDBC的功能和使用
  • 算法 --- 分治(快排)
  • 机器学习在Backtrader多因子模型中的应用
  • 2025年大学必考的十大计算机专业证书推荐:解锁你的职业未来!
  • 从0到1:解锁“预训练+微调”的AI魔法密码
  • 如何解决虚拟机网络连接问题:配置固定 IP 篇
  • 精密板料矫平机:把“皱巴巴”的金属熨成镜面
  • k8s,v1.30.4,安装使用docker
  • java面试中经常会问到的spring问题有哪些(基础版)
  • 日志打印--idf的esp32
  • 如何区分 Context Engineering 与 Prompt Engineering
  • 用AI做旅游攻略,真能比人肉整理靠谱?
  • 特斯拉“宏图计划4.0”发布!马斯克:未来80%价值来自机器人
  • Springboot3+SpringSecurity6Oauth2+vue3前后端分离认证授权-客户端
  • C++:类和对象(上)
  • 集成运算放大器的作用、选型和测量指南-超简单解读
  • 夸克网盘辅助工具 QuarkPanTool 分析
  • 代码随想录算法训练营第一天 || (双指针)27.移除元素 26.删除有序数组中的重复项 283.移动零 977.有序数组的平方
  • 从 “能说会道” 到 “能做会干”:AI Agent 技术突破,如何让人工智能拥有 “行动力”?
  • Linux 创建服务 使用systemctl 管理
  • uni app 的app端 写入运行日志到指定文件夹。
  • 腾讯云《意愿核身移动 H5》 快速完成身份验证接入
  • 国产CAD皇冠CAD(CrownCAD)建模教程:汽车驱动桥