前言
最近又到了面试的季节,今天在面试中被问到了kotlin inline 关键字 ,感觉回答的不是很好,今天研究一下它
一、inline 是什么?
inline 是kotlin 中的关键字,中文叫做内嵌 ,可以用来优化我们的代码,怎么优化呢? 通过减少方法嵌套的方式,我们接下来来验证一些这个过程。
二、未使用
代码如下
下边面是登录的一个需求
object LoginUtils {
/**
* 请求登录
* @param block true 表示登录成功
*/
fun requestLogin(block: (Boolean) -> Unit) {
.....
block(true)
}
}
---
fun main() {
LoginUtils.requestLogin {
if (it) {
logD("登录成功")
}
}
}
相信大家经常会遇到这种情况,如果成功成功做一些授权处理,那么我们将他转成java 代码看一下吧
public final void requestLogin(@NotNull Function1 block) {
Intrinsics.checkParameterIsNotNull(block, "block");
block.invoke(true);
}
ok,现在看起来一切正常,如我们所料,kotlin中的lambad 也就是我们常用的接口,使用接口回调来返回到我们的调用方。
我们会把用户信息在本地做一些缓存,避免耗费流量等一系列的原因,我们会先去查询下本地数据库是否存在
object LoginUtils {
/**
* 请求登录
* @param block true 表示登录成功
*/
fun requestLogin(block: (Boolean) -> Unit) {
//读取本地用户信息,是否存在
DbUtils.getUserInfo {
if (it.token.isNotEmpty()) {
block(true)
} else {
block(false)
}
}
}
}
--- java 代码如下
public final void requestLogin(@NotNull final Function1 block) {
Intrinsics.checkParameterIsNotNull(block, "block");
DbUtils.INSTANCE.getUserInfo((Function1)(new Function1() {
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1) {
this.invoke((User)var1);
return Unit.INSTANCE;
}
public final void invoke(@NotNull User it) {
Intrinsics.checkParameterIsNotNull(it, "it");
CharSequence var2 = (CharSequence)it.getToken();
boolean var3 = false;
if (var2.length() > 0) {
block.invoke(true);
} else {
block.invoke(false);
}
}
}));
我们这里可以看到 存在了两个 Function1 回调 分别在requestLogin和getUserInfo 参数里,像这种类似的场景在我们项目中其实是非常常见的,刚刚我们在上边我们说过inline 可以减少我们方法的嵌套,那么我们下边使用inline 关键字来优化下这块代码。
2.使用后
代码如下
接下来我们将带有lambad 的方法LoginUtil#requestLogin 和 DbUtils# getUserInfo通过inline 关键字添加修饰
--LoginUtil
public final void requestLogin(@NotNull Function1 block) {
....
DbUtils this_$iv = DbUtils.INSTANCE;
.....
String var10004 = UUID.randomUUID().toString();
.....
User it = new User("zzzqqqyyy@163.com", "123f42t523", var10004);
int var6 = false;
CharSequence var7 = (CharSequence)it.getToken();
boolean var8 = false;
if (var7.length() > 0) {
block.invoke(true);
} else {
block.invoke(false);
}
}
这是我们请求登录的方法但是我们对比之前的方法会发现,与之前的代码有些不同,我们这里发现我们上边的Function1 也就是接口回调存在两个,但是现在只有一个了,就好像他把我们 DbUtils#getUserInfo搬到了 LoginUtils#requestLogin 方法内,从而减少了一层嵌套,但是我们这里还有一层嵌套,我们接着往下看。
LoginUtil#requestLogin 方法实在 mani方法里,我们看一下
public static final void main() {
LoginUtils this_$iv = LoginUtils.INSTANCE;
...
DbUtils this_$iv$iv = DbUtils.INSTANCE;
....
String var10004 = UUID.randomUUID().toString();
....
User it$iv = new User("zzzqqqyyy@163.com", "123f42t523", var10004);
int var5 = false;
CharSequence var6 = (CharSequence)it$iv.getToken();
boolean var7 = false;
boolean it;
boolean var9;
if (var6.length() > 0) {
it = true;
var9 = false;
if (it) {
logD("登录成功");
}
} else {
....
}
}
main 里面的方法同时存在了 LoginUtil#requestLogin 和 DbUtil$getUserInfo方法,我们会发现两个Function1接口回调,都没了, 我们方法的调用顺序是main -> requestLogin -> getUserInfo 后两个都被inline 关键字 ,所以到这里可以真正的理解内嵌的意义所在了
总结
通过上边的验证我们可以确认 所有被linline 关键字修饰的方法,该方法体的内容都会被替换到调用者的方法体内,如果有lanmbad 会优化掉一个接口回调,如果我们正常的参数替换过来是没有太大意义的,所以 inline 关键字适合在存在lambad 参数的方法上进行修饰。