Kotlin学习笔记(四) - Lambda表达式

本文章借鉴了其他网络文章资源,仅做个人笔记

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() // 印度神油不好用,换伟哥!!!

你可能感兴趣的:(学习之路)