前言:什么是闭包
花括号{} 内的代码块 如果访问了 外部的环境变量,则被称为一个闭包(引用自Kotlin核心编程)
一、kotlin的lambda 表达式对比java的内部类
- Kotlin 闭包 和 java 的区别 是在于对 方法 局部变量的处理。kotlin可以修改局部变量的引用。
- java 匿名内部类 ,访问的局部变量必须添加final声明 ,并且不能修改 方法局部变量的引用 。
- java 匿名内部类的构造方法中把 局部变量 x的引用传递给了自己创建的变量 copyX 。实际访问的是copyX。
- kotlin 使用了包装这一策略,将闭包访问到的局部变量包装成了一个新的对象。
二、java的匿名内部类的闭包
三、Kotlin的闭包:上代码
class KotlinClouser {
fun testCloser(func:()->Unit){
func.invoke()
}
fun test(){
var str:String = "hello"
print(str)
testCloser { str =" what ,kotlin 的闭包可以修改外部变量的引用?" }
print(str)
}
}
fun main() {
var KotlinClouser: KotlinClouser = KotlinClouser()
KotlinClouser.test()
}
反编译后的代码
public final class KotlinClouser
{
public final void testCloser(Function0 func)
{
Intrinsics.checkParameterIsNotNull(func, "func");
func.invoke();
}
public final void test()
{
// 这里将我们定义的 str 包装成了 ObjectRef 对象。
// kotlin的闭包虽然可以修改局部变量的引用,但也产生了额外的性能消耗(包装操作)
kotlin.jvm.internal.Ref.ObjectRef str = new kotlin.jvm.internal.Ref.ObjectRef();
str.element = "hello";
String s = (String)str.element;
boolean flag = false;
System.out.print(s);
testCloser((Function0)new Function0(str) {
public volatile Object invoke()
{
invoke();
return Unit.INSTANCE;
}
public final void invoke()
{
$str.element = " what ,kotlin \u7684\u95ED\u5305\u53EF\u4EE5\u4FEE\u6539\u5916\u90E8\u53D8\u91CF\u7684\u5F15\u7528\uFF1F";
}
final kotlin.jvm.internal.Ref.ObjectRef $str;
{
$str = objectref;
super(0);
}
}
);
s = (String)str.element;
flag = false;
System.out.print(s);
}
public KotlinClouser()
{
}
}
四、总结:Kotlin 和java 对闭包的处理方式的不同。
- Kotlin 通过包装局部变量 ,处理闭包的访问,java则是传递引用 。
- Kolin 的闭包 比 java 的闭包开销 要大 ,所以Kotlin引入Inline 进行优化