本文章借鉴了其他网络文章资源,仅做个人笔记
1、开篇
以下在main函数中定义了一个名为codeBlock的代码块,可以理解成是一个函数,这个函数接收一个名为f的Int类型参数,函数内部进行了打印操作,同时返回了一个3作为返回值,那么也就是说,codeBlock的返回值类型是Int类型(Kotlin类型自动推断机制),调用该函数,传入2,并用result接收函数的返回值,再打印result,可以发现整体打印结果不难理解
fun main(args: Array) {
val codeBlock = { f: Int ->
println("f=$f")
3
}
var result = codeBlock(2)
println("result = $result")
// 调用结果:
// f=2
// result = 3
}
2、原理
我们尝试看一下codeBlock在Java字节码中的类型,发现是一个匿名内部类
println(codeBlock.javaClass) // class MyLambdaDemoKt$main$codeBlock$1
遍历该匿名内部类所有的方法,经过和普通类对比,发现多出3个方法:invoke、invoke、getArity
for (m in codeBlock.javaClass.methods) {
println(m.name)
}
// invoke
// invoke
// toString
// getArity
// wait
// wait
// wait
// equals
// hashCode
// getClass
// notify
// notifyAll
我们这样找到invoke方法,然后进入invoke源码观看,我们发现,我的天呐~!进入了Java的Method.java类中的public Object invoke(Object obj, Object… args)方法,瞬间一切好像都明白了些什么,没错,就是反射里常用的method.invoke方法
for (m in codeBlock.javaClass.methods) {
if ("invoke" == m.name) {
m.invoke(codeBlock, 10)
}
}
// Java的Method.java类中的invoke方法
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
不多说了,直接调一下试试吧(咦?为什么有两个一模一样的invoke方法,有兴趣的同学可以跟一下源码,欢迎留言)
for (m in codeBlock.javaClass.methods) {
if ("invoke" == m.name) {
m.invoke(codeBlock, 10)
// 调用结果:
// f=10
// f=10
}
}
我们把两个invoke方法的一些变量打印出来
for (m in codeBlock.javaClass.methods) {
if ("invoke" == m.name) {
println("--------------------")
println(m.defaultValue)
println(m.genericReturnType)
println(m.isBridge)
println(m.isDefault)
println(m.returnType)
}
}
// 打印结果:
--------------------
null
class java.lang.Object
true
false
class java.lang.Object
--------------------
null
int
false
false
int
3、再举个栗子
// 1、你提前给我了"1瓶神油"和"1粒伟哥"和"会呼吸的杜蕾斯",然后你让我在走廊等你,你把302房间钥匙给了我,我有权利给你放东西,于是我开始放东西,我先放入你给我的印度神油(带包装盒)和杜蕾斯(带包装盒):_302房间(印度神油, 杜蕾斯)
// 2、你在房间里一顿折腾,你先判断道具1是不是1瓶神油,道具2是不是会呼吸的杜蕾斯,然后如果是,就告诉我OK(你太忙,只告诉我true或者false,没有多说一句话)
// 3、于是我拿到了你的反馈意见:var result = _302房间(印度神油, 杜蕾斯)
// 4、我根据你的反馈意见,得出结论,到底印度神油好用不好用
// 5、具体逻辑和场景,请自行脑补,欢迎留言
// 定义
fun myfun(印度神油: String, 伟哥: String, 杜蕾斯: String, _302房间: (String, String) -> Boolean): () -> Unit {
var result = _302房间(印度神油, 杜蕾斯)
var a = { println("印度神油好用!!!") }
var b = { println("印度神油不好用,换伟哥!!!") }
return if (result) a else b
}
// 调用1(正常情况)
var result = myfun("1瓶神油", "1粒伟哥", "会呼吸的杜蕾斯") { 道具1, 道具2 ->
if (道具1 == "1瓶神油" && 道具2 == "会呼吸的杜蕾斯") true else false
}
result() // 印度神油好用!!!
// 调用2(你给我的是假的印度神油)
var result = myfun("假的印度神油", "1粒伟哥", "会呼吸的杜蕾斯") { 道具1, 道具2 ->
if (道具1 == "1瓶神油" && 道具2 == "会呼吸的杜蕾斯") true else false
}
result() // 印度神油不好用,换伟哥!!!
// 定义
fun myfun(印度神油: String, 伟哥: String, 杜蕾斯: String, _302房间: (String, String) -> Boolean): () -> Unit {
var result = _302房间("假的印度神油", 杜蕾斯)
var a = { println("印度神油好用!!!") }
var b = { println("印度神油不好用,换伟哥!!!") }
return if (result) a else b
}
// 调用(你虽然给了我1瓶神油,但是,我给你的是假的印度神油)
var result = myfun("1瓶神油", "1粒伟哥", "会呼吸的杜蕾斯") { 道具1, 道具2 ->
if (道具1 == "1瓶神油" && 道具2 == "会呼吸的杜蕾斯") true else false
}
result() // 印度神油不好用,换伟哥!!!