面试题答案
一键面试Kotlin内联函数相比于普通函数的优势
- 减少函数调用开销:普通函数调用会有压栈、传参、执行函数体、出栈等开销。内联函数在编译时,函数体直接替换调用处,避免了这些开销,提升了性能,尤其是在频繁调用的情况下。
- 支持具体化类型参数:普通函数无法在运行时获取泛型参数的实际类型,而内联函数结合
reified
关键字可以做到。
性能提升场景举例
例如,一个高阶函数频繁被调用,且函数体逻辑简单的场景。
fun measureTime(block: () -> Unit): Long {
val startTime = System.currentTimeMillis()
block()
return System.currentTimeMillis() - startTime
}
inline fun measureTimeInline(block: () -> Unit): Long {
val startTime = System.currentTimeMillis()
block()
return System.currentTimeMillis() - startTime
}
fun main() {
var totalTime = 0L
for (i in 0 until 100000) {
totalTime += measureTime {
// 简单逻辑,比如打印或计算一个简单表达式
println(i)
}
}
println("普通函数总耗时: $totalTime")
totalTime = 0L
for (i in 0 until 100000) {
totalTime += measureTimeInline {
println(i)
}
}
println("内联函数总耗时: $totalTime")
}
在上述例子中,measureTimeInline
作为内联函数,由于函数体直接替换到调用处,没有函数调用开销,对于大量调用场景,性能会比普通的measureTime
函数有明显提升。
内联函数中reified类型参数的作用和使用场景
- 作用:
reified
关键字使内联函数能够在运行时获取泛型类型参数的实际类型,而普通函数的泛型类型参数在编译后会被擦除。 - 使用场景:
- 类型检查:例如在一个通用的
filter
函数中,可以在运行时检查集合元素的类型。
- 类型检查:例如在一个通用的
inline fun <reified T> List<*>.filterIsInstance(): List<T> {
val result = mutableListOf<T>()
for (element in this) {
if (element is T) {
result.add(element)
}
}
return result
}
fun main() {
val mixedList = listOf(1, "two", 3, "four")
val intList = mixedList.filterIsInstance<Int>()
println(intList)
}
- **反射操作**:当需要基于泛型类型进行反射操作时,`reified`类型参数可以提供实际类型信息。例如创建对象实例。
inline fun <reified T> createInstance(): T {
return T::class.java.newInstance()
}
但需注意,createInstance
函数中T::class.java.newInstance()
这种反射方式在现代Java中已不推荐,只是用于说明基于reified
进行反射操作的思路。实际可使用kotlin-reflect
库结合reified
进行更安全的反射实例创建。