-
Notifications
You must be signed in to change notification settings - Fork 116
高阶函数实现原理
zhangpan edited this page Aug 17, 2021
·
5 revisions
一、Kotlin的高阶函数
如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数。
高阶函数的基本语法:(String,Int)-> Unit
->左边部分用来声明函数接收什么类型的参数,多个参数之间用逗号隔开,如果不接收任何参数,可用括号表示。而->右边部分用于声明该函数的返回类型,没有返回值就使用Unit,相当于void。
举个例子:
fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
上述函数接收两个Int类型的参数,和一个函数类型的参数。这个函数即为一个高阶函数。接下来看如何调用高阶函数。
首先定义两个函数
fun plus(num1: Int, num2: Int): Int {
return num1 + num2
}
fun minus(num1: Int, num2: Int): Int {
return num1 - num2
}
接着讲上述两个函数作为num1AndNum2函数的参数如下:
fun main() {
val num1 = 100
val num2 = 80
val result1 = num1AndNum2(num1, num2, ::plus)
val result2 = num1AndNum2(num1, num2, ::minus)
print("result1 = $result1")
print("result2 = $result2")
}
打印结果:
result1 = 180
result2 = 20
可以看到,想要使用高阶函数需要定义一个与高阶函的数参数匹配的函数作为参数才行,这样写相当麻烦。
其实,kotlin支持 多种方式调用高阶函数,如lambada表达式、匿名函数、成员引用等。其中Lambda表达式是最常见的高阶函数调用方式。上述代码使用Lambda表达式的写法如下:
fun main() {
val num1 = 100
val num2 = 80
val result1 = num1AndNum2(num1, num2) { n1, n2 ->
n1 + n2
}
val result2 = num1AndNum2(num1, num2){ n1, n2 ->
n1 - n2
}
print("result1 = $result1")
print("result2 = $result2")
}
因为kotlin代码最终也是会被编译成字节码的,因此可以将上述高阶函数编译成的字节码,再反编译成java的代码,得到如下结果:
public final int num1AndNum2(int num1, int num2, @NotNull Function2 operation) {
Intrinsics.checkParameterIsNotNull(operation, "operation");
return ((Number)operation.invoke(num1, num2)).intValue();
}
可以看到,将kotlin代码编程java代码后,高阶函数变成了一个 Function2 参数。而这个Function2是kotlin中定义的一个接口:
public interface Function2<in P1, in P2, out R> : Function<R> {
/** Invokes the function with the specified arguments. */
public operator fun invoke(p1: P1, p2: P2): R
}
也就是说,kotlin 高阶函数的实现其实使用的是匿名内部类。
- JMM与volatile关键字
- synchronized的实现原理
- synchronized等待与唤醒机制
- AQS的实现原理
- ReentrantLock的实现原理
- ReentrantLock等待与唤醒机制
- CAS、Unsafe类以及Automic并发包
- ThreadLocal的实现原理
- 线程池的实现原理
- Java线程中断机制
- 多线程与并发常见面试题
- Android基础知识汇总
- MVC、MVP与MVVM
- SparseArray实现原理
- ArrayMap的实现原理
- SharedPreferences
- Bitmap
- Activity的启动模式
- Fragment核心原理
- 组件化项目架构搭建
- 组件化WebView架构搭建
- 为什么 Activity.finish() 之后 10s 才 onDestroy ?
- Binder与AIDL
- Binder实现原理
- Android系统启动流程
- InputManagerService
- WindowManagerService
- Choreographer详解
- SurfaceFlinger
- ViewRootImpl
- ActivityManagerService
- APP启动流程
- PMS安装与签名校验
- Dalvik与ART
- 内存优化策略
- UI界面及卡顿优化
- App启动优化
- ANR问题
- 包体积优化
- APK打包流程
- 电池电量优化
- Android屏幕适配
- 线上性能监控1--线上监控切入点
- 线上性能监控2--Matrix实现原理
- Glide实现原理
- OkHttp实现原理
- Retrofit实现原理
- RxJava实现原理
- RxJava中的线程切换与线程池
- LeakCanary实现原理
- ButterKnife实现原理
- ARouter实现原理
- Tinker实现原理
- 2. 两数相加
- 19.删除链表的倒数第 N 个结点
- 21. 合并两个有序链表
- 24. 两两交换链表中的节点
- 61. 旋转链表
- 86. 分隔链表
- 92. 反转链表 II
- 141. 环形链表
- 160. 相交链表
- 206. 反转链表
- 206 反转链表 扩展
- 234. 回文链表
- 237. 删除链表中的节点
- 445. 两数相加 II
- 面试题 02.02. 返回倒数第 k 个节点
- 面试题 02.08. 环路检测
- 剑指 Offer 06. 从尾到头打印链表
- 剑指 Offer 18. 删除链表的节点
- 剑指 Offer 22. 链表中倒数第k个节点
- 剑指 Offer 35. 复杂链表的复制
- 1. 两数之和
- 11. 盛最多水的容器
- 53. 最大子序和
- 75. 颜色分类
- 124.验证回文串
- 167. 两数之和 II - 输入有序数组 -169. 多数元素
- 189.旋转数组
- 209. 长度最小的子数组
- 283.移动0
- 303.区域和检索 - 数组不可变
- 338. 比特位计数
- 448. 找到所有数组中消失的数字
- 643.有序数组的平方
- 977. 有序数组的平方