Kotlin學習筆記(四)
阿新 • • 發佈:2019-01-25
本文章借鑑了其他網路文章資源,僅做個人筆記
1、開篇
以下在main函式中定義了一個名為codeBlock的程式碼塊,可以理解成是一個函式,這個函式接收一個名為f的Int型別引數,函式內部進行了列印操作,同時返回了一個3作為返回值,那麼也就是說,codeBlock的返回值型別是Int型別(Kotlin型別自動推斷機制),呼叫該函式,傳入2,並用result接收函式的返回值,再列印result,可以發現整體列印結果不難理解
fun main(args: Array<String>) { 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() // 印度神油不好用,換偉哥!!!