1. 概述
在本文中,我们将探讨一些常见的 Kotlin 面试问题,按照初级和高级两个层次进行分类,便于理解和准备。
这些问题涵盖了 Kotlin 的核心语法、语言特性、与 Java 的互操作性,以及一些高级概念如协程、高阶函数等。对于准备 Kotlin 相关岗位面试的开发者来说,是一份不错的参考资料。
2. 初级问题
2.1 什么是 Kotlin?它与 Java 如何互操作?
Kotlin 是由 JetBrains 开发的基于 JVM 的通用编程语言。它是一种静态类型语言,支持过程式、函数式和面向对象编程。
Kotlin 与 Java 的互操作性非常强,因为 Kotlin 编译器生成的字节码与 Java 编译器生成的字节码完全兼容。这意味着你可以在一个项目中同时使用 Kotlin 和 Java,相互调用类和方法。
此外,Kotlin 提供了一些实用特性,如范围表达式、扩展函数、空安全、智能类型转换等,使其成为 Java 的一个更现代化替代方案。
✅ Google 官方推荐 Kotlin 作为 Android 开发的首选语言。
2.2 Kotlin 中变量声明的类型有哪些?
Kotlin 中使用 val
和 var
关键字声明变量:
val userName: String = "John"
var age = 25
val
:不可变变量(只读),只能赋值一次。var
:可变变量,可以多次赋值。
如果没有指定类型,Kotlin 会通过类型推断自动识别变量类型。
另外,还可以使用 const
关键字配合 val
声明编译时常量。
2.3 val
和 const
有什么区别?
val
:运行时不可变变量,可以在运行时初始化,例如通过函数调用赋值。const
:编译时常量,必须在声明时赋值,且值必须是基本类型或字符串。
示例:
val welcomeMsg: String = "Hello $userName"
const val FILE_EXTENSION: String = ".jpg"
⚠️ const
只能用于 val
,且不能赋值为函数调用或构造函数。
2.4 如何在 Kotlin 中创建构造函数?
Kotlin 支持两种构造函数:
- 主构造函数(Primary Constructor):定义在类头中,通常用于初始化属性。
- 次构造函数(Secondary Constructor):定义在类体内,用于提供额外的初始化逻辑。
主构造函数示例:
class Person(var firstName: String, var lastName: String) {
var age: Int = 0
}
val person = Person("John", "Smith")
次构造函数示例:
class Person(var firstName: String, var lastName: String) {
var age: Int = 0
constructor(firstName: String, age: Int) {
this.firstName = firstName
this.age = age
}
constructor(firstName: String, lastName: String, age: Int): this(firstName, lastName) {
this.age = age
}
}
2.5 Kotlin 中的字符串插值是什么?
Kotlin 支持两种字符串插值方式:
$变量名
:插入变量。${表达式}
:插入表达式结果。
示例:
val name = "John"
val greeting = "Hello $name" // Hello John
val seconds = "${60 * 60 * 24 * 365} seconds" // 31536000 seconds
2.6 Kotlin 中的空安全机制是什么?
Kotlin 默认不允许变量为 null
,以避免 NullPointerException
。
如果需要允许变量为空,可以使用 ?
声明可空类型:
var name: String? = null
Kotlin 提供了多种空处理操作符:
?.
:安全调用。?:
:Elvis 运算符,提供默认值。!!
:非空断言,若为 null 抛出异常。
2.7 Kotlin 中的 data class 是什么?
data class 是一种简化 POJO(普通 Java 对象)定义的类,自动实现 equals()
、hashCode()
、toString()
等方法。
只需添加 data
关键字即可:
data class Person(var firstName: String, var lastName: String)
✅ data class 还会自动生成 copy()
、componentN()
等方法。
2.8 如何在 Kotlin 中创建单例类?
Kotlin 提供了 object
关键字来实现单例模式:
object SimpleSingleton
该方式在编译时自动实现线程安全的懒加载机制。
2.9 Kotlin 中的双感叹号(!!)操作符是什么?
!!
是非空断言操作符。如果变量为 null
,它会抛出 NullPointerException
。
适用于你确定变量不会为 null 的场景:
val name: String? = getName()
val length = name!!.length // 若 name 为 null,抛异常
⚠️ 使用时要小心,避免运行时崩溃。
2.10 Kotlin 中的 range 表达式是什么?
range 表达式用于表示一个值的范围,支持迭代和判断值是否在范围内。
Kotlin 提供了多种写法:
(1..10) // 从 1 到 10
(1.rangeTo(10)) // 同上
(10.downTo(1)) // 从 10 到 1
('a'..'z') // 从 a 到 z
(1..10 step 2) // 步长为 2 的范围
还可以使用 until
、reverse
、first
、last
等方法进行操作。
2.11 Kotlin 中的 when 是什么?
when
是 Kotlin 中的条件判断语句,类似于 Java 的 switch-case
,但功能更强大。
示例:
when (person.firstName) {
"Mike" -> println("hello!")
"John" -> println("howdy!")
else -> println("hi!")
}
✅ Kotlin 的 when
支持表达式、类型检查、范围匹配等多种用法,且不需要 break
。
2.12 Kotlin 中有哪些访问修饰符?默认是哪个?
Kotlin 支持以下访问修饰符:
修饰符 | 作用范围 |
---|---|
public |
默认修饰符,全局可见 |
private |
当前文件或类内可见 |
protected |
当前类及其子类可见 |
internal |
同一模块内可见 |
⚠️ Kotlin 没有 Java 的 default
包访问权限,而是使用 internal
。
2.13 Kotlin 中的 open 是什么?
Kotlin 默认所有类和方法都是 final
(不可继承/重写),若希望允许继承或重写,需要使用 open
关键字。
例如:
open class Animal {
open fun speak() {
println("Animal speaks")
}
}
✅ open
是 Java 中 final
的反义词。
3. 高级问题
3.1 Kotlin 相比 Java 有哪些优势?
Kotlin 作为 Java 的现代化替代语言,具有以下优势:
- ✅ 更简洁的语法,减少样板代码。
- ✅ 空安全机制,减少 NPE。
- ✅ 扩展函数,无需继承或装饰器。
- ✅ 范围表达式、字符串插值等语法糖。
- ✅ 协程支持,简化异步编程。
- ✅ 支持函数式编程特性(高阶函数、lambda 表达式)。
- ✅ 与 Java 完全互操作。
- ✅ Google 官方推荐用于 Android 开发。
3.2 inline 和 infix 函数分别是什么?
inline 函数
inline
函数在编译时将函数体直接插入调用处,避免创建额外的 lambda 对象,提升性能。
示例:
inline fun isEven(number: Int): Boolean {
return number % 2 == 0
}
val resultList = (1..10).filter { isEven(it) }
✅ 适用于频繁调用的 lambda 函数。
infix 函数
infix
函数允许使用中缀表达式调用,使代码更接近自然语言。
示例:
infix fun Int.times(value: String): String {
return value.repeat(this)
}
val result = 3 times "hello" // "hellohellohello"
✅ 常见的 infix 函数有 to
、and
、or
等。
3.3 lazy 和 lateinit 有什么区别?
特性 | lazy | lateinit |
---|---|---|
类型 | val |
var |
初始化方式 | Lambda 表达式 | 可在任意地方赋值 |
是否允许 null | 否 | 否(未初始化会抛异常) |
多次赋值 | 否 | 是 |
支持类型 | 所有类型 | 不支持基本类型 |
示例:
val lazyValue: String by lazy {
"Initialized"
}
lateinit var name: String
name = "John"
3.4 fold 和 reduce 函数的区别是什么?
两者都用于集合的折叠操作,区别在于是否提供初始值。
fold
:提供初始值,从初始值开始累加。reduce
:不提供初始值,从集合第一个元素开始。
示例:
val sum1 = (1..10).fold(10) { acc, i -> acc + i } // 65
val sum2 = (1..10).reduce { acc, i -> acc + i } // 55
✅ fold
支持更改结果类型(通过初始值类型)。
3.5 Kotlin 中的协程是什么?
协程是一种轻量级的并发编程方式,允许异步、非阻塞地执行任务。
Kotlin 提供了 kotlinx-coroutines
库,支持:
- 挂起函数(
suspend
) - 协程构建器(
launch
、async
) - 作用域(
CoroutineScope
) - 调度器(
Dispatchers
)
示例:
GlobalScope.launch {
val result = async { fetchData() }.await()
println(result)
}
✅ 协程比线程更高效,适合大量并发任务。
3.6 Kotlin 中的 companion object 是什么?
Kotlin 没有静态成员,但可以通过 companion object
实现类似静态方法的调用。
示例:
class Person(val name: String) {
companion object {
val defaultPerson = Person("Mike")
}
}
println(Person.defaultPerson.name) // Mike
✅ companion object
是一个单例对象,可以拥有名称,也可以实现接口。
3.7 Kotlin 中的位运算符有哪些?
Kotlin 支持常见的位运算符,但命名更直观:
Java 运算符 | Kotlin 运算符 |
---|---|
` | ` |
& |
and |
^ |
xor |
~ |
inv() |
位移操作符:
shl
:左移shr
:带符号右移ushr
:无符号右移
示例:
assert(3 shl 3 == 24)
assert(12 shr 2 == 3)
assert(-1 ushr 1 == Int.MAX_VALUE)
4. 总结
本文整理了 Kotlin 面试中常见的初级和高级问题,覆盖了语言特性、语法糖、面向对象、函数式编程、并发等多个方面。
这些问题虽然基础,但往往能体现开发者对 Kotlin 的掌握深度。建议在理解的基础上多做实践,才能在面试中游刃有余。
✅ 进阶建议:深入理解协程、高阶函数、DSL、泛型系统等高级特性,对 Android 开发者尤为重要。