Android 高级工程师面试:Kotlin 语法基础 近1年高频追问 22 题

文章目录

学习建议

目标层级 建议
初级 掌握基础层 8 题:空安全、val/vardata classwhen;工程联想看每题追问第 1 条
中级 通读全文;进阶层能讲清作用域函数选型、object/companion、Lambda/SAM、解构与默认参数
高级 核心层 by lazy/by viewModels、Kotlin vs Java 概览必答;能串联「空安全→类型建模→委托→Jetpack」工程链路

基础层(8 题)

#1 Kotlin 空安全体系:?!!?: 怎么用? 🔥

标准回答

Kotlin 默认非空,可空类型显式标 ?,编译期拦截大部分 NPE;?. 遇 null 短路,?: Elvis 给默认值,!! 强制非空但 null 仍抛 NPE。

面试官可能继续追问

  • Android 里空安全常见踩坑?

    解析 Intent extra、网络 JSON 用 ?: 兜底;UI 层滥用 !! 是 NPE 高发区。

  • String? 能直接赋给 String 吗?

    不能,需 ?:、安全调用或 let 收窄后再用。


#2 valvar 有什么区别? 🔥

标准回答

val 只读引用不可重新赋值,var 可变引用可改指向;val 不保证对象内容不可变,只锁引用,编译期常量用 const val

面试官可能继续追问

  • Android 里 val/var 怎么选?

    ViewModel 对外状态、Repository 返回值用 val;Compose remember 管理可变 UI 状态时常配 var

  • val list 还能 add 吗?

    能,val 只禁止换引用,不禁止改集合内容。


#3 data class 解决了什么问题? 🔥

标准回答

自动生成 equals/hashCode/toString/copy/解构,替代 Java Bean 样板;主构造 val/var 参与生成,copy 支持不可变更新。

面试官可能继续追问

  • Android 里 data class 用在哪?

    Room 实体、网络 DTO、UiState 建模;DiffUtil/LazyColumn 依赖正确 equals

  • data class 能继承类吗?

    不能继承普通类,可实现接口;继承用 sealed class


#4 sealed class 是什么?和 enum 怎么选? 🔥

标准回答

sealed class 限制子类在同一文件/模块,配合 when 穷举分支,编译器校验完备性;子类可携带不同数据,全覆盖时可省略 else

面试官可能继续追问

  • Android 里 sealed class 典型用法?

    UI 状态 Loading/Success/Errorwhen(state) 分支渲染,编译期检查漏分支。

  • sealed interfacesealed class 区别?

    interface 可多实现、无状态;class 可有构造与字段,单继承。


#5 when 表达式和 Java switch 有什么不同? 🔥

标准回答

when 是表达式可返回值,支持类型判断、范围、多条件,无需 break;分支匹配后自动结束,常配合 is 触发智能转换。

面试官可能继续追问

  • Android 里 when 常见场景?

    处理 sealed classUiState、权限结果、网络错误码;Compose 按状态分支渲染。

  • when 没有 else 会编译失败吗?

    作表达式且未穷尽所有情况时会报错;sealed 全覆盖可省略。


#6 什么是智能转换(smart cast)? 🔥

标准回答

编译器在判空或 is 检查后自动收窄类型,省去手动强转;局部 val 在检查点后类型已知,var 或可被并发改写时失效。

面试官可能继续追问

  • Android 里 smart cast 例子?

    if (binding != null) 后直接用 binding.textwhen (event) is ShowToast 后访问 event.message

  • 为什么 var 不能 smart cast?

    另一线程可能改值,编译器无法保证检查与使用间类型不变。


#7 扩展函数是什么?为什么不能改原类? 🔥

标准回答

给已有类「追加」方法,编译为静态函数,第一个参数是接收者;不改原类字节码,按声明时静态类型解析,非多态。

面试官可能继续追问

  • Android 里扩展函数常见写法?

    Context.showToast()View 可见性工具、Modifier 链式扩展。

  • 扩展函数能被子类覆盖吗?

    不能,按声明时静态类型解析,非多态。


#8 lateinitlazy 的区别? ⭐

标准回答

lateinit var 延迟赋值可变非空引用,未初始化访问抛异常;lazy 延迟初始化只读值,首次访问才算,默认 SYNCHRONIZED 线程安全。

面试官可能继续追问

  • Android 里 lateinitlazy 怎么用?

    lateinit 用于 onCreate 注入的 ViewBindinglazy 延迟创建昂贵对象,但勿持有 Context 泄漏。

  • lateinit 能用于可空类型吗?

    不能,只适用于非空引用;可空场景用可空类型或 lazy


进阶层(7 题)

#9 作用域函数 let/run/apply/also/with 怎么选? 🔥

标准回答

let :转结果,用 it

run :配置并返回,用 this

apply :配置返回自身;

also :副作用返回自身;

with :非扩展版 run

面试官可能继续追问

  • Android 里作用域函数怎么选?

    可空 user?.let { bind(it) };构建 Bundle/Requestapply;调试旁路用 also

  • 链式里 applyalso 混用会乱吗?

    会,团队约定一种风格;配置对象用 apply,调试打印用 also


#10 objectcompanion object 的区别? ⭐

标准回答

object 是单例或匿名对象,编译为单例类;companion object 是类的伴生成员容器,成员可通过类名直接访问,类似 Java static

面试官可能继续追问

  • Android 里 object/companion 用在哪?

    object 做无状态工具单例;companion objectconstnewInstance() 工厂方法。

  • objectcompanion object 能同名吗?

    companion object 可命名,便于 Java 侧 Companion 访问;一般保持默认即可。


#11 Kotlin 集合 List/Map/Set 与 Java 有何不同? ⭐

标准回答

Kotlin 区分只读与可变:List 只读、MutableList 可变;只读是协变视图,运行时仍可能是 ArrayListlistOf 只读、mutableListOf 可变。

面试官可能继续追问

  • Android 里只读/可变集合怎么用?

    Repository 对外返回 List<T>;内部 mutableListOf 维护,发布前 toList() 再暴露。

  • 只读 List 真能防修改吗?

    不能绝对防,底层可变实现仍可被强转修改;约定+toList() 拷贝更安全。


#12 Lambda 与高阶函数在 Android 中怎么用? ⭐

标准回答

Lambda 是匿名函数字面量,高阶函数把函数当参数或返回值;非 inline lambda 可能生成对象,尾随 lambda 让 DSL 更简洁。

面试官可能继续追问

  • Android 里 Lambda 常见场景?

    RecyclerView/Compose 点击回调、filter/map 处理列表数据。

  • Lambda 捕获外部变量有什么限制?

    val 或 effectively final,与 Java 匿名类规则一致。


#13 SAM 转换是什么? ⭐

标准回答

Kotlin 调用 Java 单抽象方法接口时,lambda 可自动转为 SAM;编译器生成适配器实现唯一抽象方法,要求 @FunctionalInterface 或 Kotlin fun interface

面试官可能继续追问

  • Android 里 SAM 转换例子?

    View.setOnClickListener { }Runnable { };自定义 fun interface 回调。

  • Kotlin 定义的 fun interface 优势?

    明确 SAM 语义,lambda 与 Java 互操作更稳定,Retrofit 回调常用。


#14 解构声明怎么用? ⭐

标准回答

componentN() 支持一对多拆包,如 val (a, b) = pairdata class 自动生成 component1..N,自定义类可实现 operator fun component1()。常见写法:for ((key, value) in map)、对 data class 一次拆多字段。

面试官可能继续追问

  • 解构在 Android 里常见吗?

    for ((key, value) in map) 遍历;对 data class 网络响应一次拆多字段。

  • 解构 data class 会创建中间对象吗?

    编译为 componentN() 调用,无额外包装对象。


#15 默认参数与命名参数怎么用? ⭐

标准回答

参数可设默认值,调用时可按名传参,减少重载;编译器为缺省参数生成合成重载,Java 调用侧需 @JvmOverloads

面试官可能继续追问

  • Android 里默认参数怎么用?

    自定义 View/Composable 多可选配置;测试数据 User(isVip = true) 可读性更好。

  • 默认参数值每次调用都重新计算吗?

    是,每次调用求值;昂贵默认应用 lazy 或工厂方法。


核心层(7 题)

#16 属性委托 by lazy 的原理与用法? ⭐

标准回答

by lazy 把属性 getter 委托给 Lazy 实例,首次访问才算值;LazyThreadSafetyMode 控制同步,默认 SYNCHRONIZED

面试官可能继续追问

  • Android 里 by lazy 注意什么?

    延迟创建 Gson 等昂贵对象可以;Activity 中 lazy 持有 Context 易泄漏。

  • lazylateinit 选型?

    只读且昂贵用 lazyvar 且稍后赋值用 lateinit


#17 by viewModels 委托解决了什么? 🔥

标准回答

Activity/Fragment 用属性委托自动获取/缓存 ViewModel,内部通过 ViewModelStore + Factory 懒获取,旋转不丢状态。

面试官可能继续追问

  • by viewModels 在 Android 里怎么用?

    private val vm: MainViewModel by viewModels(),旋转屏幕不丢状态;多 Fragment 共享用 activityViewModels()

  • by lazy { ViewModelProvider(...) } 比?

    viewModels 官方封装,自动处理 Factory 与 store 键,更少样板代码。


#18 Kotlin 与 Java 语法概览:现代 Android 为何首选 Kotlin? ⭐

标准回答

Kotlin 与 Java 100% JVM 互操作,同样编译为字节码;语法更简洁,有空安全、扩展函数、数据类、密封类等语法糖,协程(K2)是异步核心卖点。

面试官可能继续追问

  • 为什么现代 Android 首选 Kotlin?

    Google 官方推荐,Jetpack/Compose 与 KTX 均 Kotlin 优先;空安全与协程降低 NPE 与异步样板代码。

  • Kotlin 比 Java 慢吗?

    运行时同为 JVM 字节码,性能同级;差异在开发效率,非执行速度。


#19 typealias 有什么用? 💡

标准回答

为已有类型起别名,编译期替换、运行时等价于原类型,可简化长泛型签名。例如 typealias NetworkMap = Map<String, List<Dto>>、回调类型 typealias ClickListener = (View) -> Unit,减少嵌套括号、提升接口可读性。

面试官可能继续追问

  • typealias 在 Android 工程里有用吗?

    回调 typealias ClickListener = (View) -> Unit;长泛型 Map<String, List<Dto>> 起别名提升可读性。

  • typealiasimport 重命名区别?

    import 只改引用名;typealias 可在模块内定义新类型名供多处复用。


#20 可空类型常见 NPE 场景与常见变通写法? 💡

标准回答

Kotlin 侧 NPE 常见来源:!! 滥用、未初始化的 lateinitlazy 递归初始化;Fragment 生命周期结束后仍访问视图也会崩。

面试官可能继续追问

  • Android 里 Kotlin NPE 常见场景?

    !! 滥用、未初始化 lateinit、Fragment view 销毁后仍访问。

  • Elvis 右侧能抛异常吗?

    可以,?: throw IllegalStateException() 用于不变量校验。


#21 只读集合与可变集合怎么选? 💡

标准回答

对外暴露只读 List<T>/Map<K,V>,内部用 MutableList 维护,发布前 toList()/toMap() 防御性拷贝,防止调用方意外修改。

面试官可能继续追问

  • Android 里只读集合最佳实践?

    Repository 返回 List<Item> 给 UI;内部可变、对外 toList() 发布。

  • Collections.unmodifiableList 还要用吗?

    Kotlin 侧优先 List+toList();与 Java 互操作时可保留。


#22 inlinereified 一句话是什么? 💡

标准回答

inline 把函数体内联到调用处,减少 lambda 对象;reified T 仅用于 inline 函数,编译期展开,运行时可用 T::class

面试官可能继续追问

  • Android 里 inline/reified 用在哪?

    viewModels<T>()startActivity<T>() 等 Jetpack 扩展依赖编译期展开类型。

  • 所有函数都该 inline 吗?

    不应,只 inline 小函数+高阶参数;大函数内联会膨胀字节码。


面试策略速查

面试等级 建议掌握
初级 ★★★☆☆
中级 ★★★★☆
高级 ★★★★★

必背知识(🔥)

空安全 ?/?:/!!val/vardata class/sealed classwhen+smart cast;扩展函数;作用域函数选型;SAM 转换;by viewModels

高频追问

lateinitlazy 区别」「letapply 怎么选」「sealed classenum」「为什么 Kotlin 能减少 NPE」「data classcopy 用途」

加分项(💡)

typealias;只读/可变集合防御性拷贝;可空链常见变通写法;inline/reified 概念(深度留 K4)

容易踩坑

滥用 !!lateinit 未赋值就访问;只读 List 当绝对不可变;作用域函数嵌套过深可读性崩;lazy 持有 Activity Context 泄漏


完整链路一句通

Kotlin 语法一条线 :默认非空+可空类型消灭 NPE,data/sealed 建模 UI 状态,when+smart cast 穷举分支,扩展函数与作用域函数减少样板,属性委托 lazy/viewModels 对接 Jetpack 生命周期------语法扎实后再上协程(K2)。


相关推荐

【Kotlin 初学者】为什么要学Kotlin

Android 高级工程师面试:Java 基础知识 近1年高频追问 22 题

相关推荐
想你依然心痛2 小时前
嵌入式日志系统:分级日志、环形缓冲区与远程输出——运行时调试、非侵入
android·前端·javascript
用户69371750013843 小时前
AI Agent 里的 Loop 到底是什么?
android·前端·后端
雨辰AI3 小时前
【零基础实战】大模型入门面试 100 问:基础概念 + 环境实操(一问一答版,直接背诵)
人工智能·ai·面试·职场和发展·ai编程
海天鹰4 小时前
安卓分割空字符串数组长度为1
android
云技纵横4 小时前
@Async 默认执行器又炸了:SimpleAsyncTaskExecutor 为什么不是线程池?
后端·面试
Coffeeee4 小时前
从 Android 15 到 Android 17,谷歌猝不及防的音频改动
android·前端·google
uhakadotcom4 小时前
什么是 “无界限的列表积累” 问题
后端·面试·github
KaifuZeng4 小时前
通信与接口协议面试八、CAN通信
单片机·嵌入式硬件·面试·通信与接口协议