Kotlin:SAM杂谈
2018-05-28 本文已影响14人
泪已无痕
SAM(Single Abstract Method)接口或函数式接口,指的是只有一个抽象方法的类或接口,其主要目的是为了以lambda的形式调用Java API,比如我们有以下Java接口:
public interface OnClickListener {
void onClick(View view);
}
在Kotlin中,如果没有SAM转换,那么我们必须通过以下方式实现:
button.setOnClickListener(object: OnClickListener() {
override fun onClick(view: View?) {
}
})
有了SAM转换,我们就可以通过传递lambda的方式实现:
button.setOnClickListener { view -> }
通过对比,我们可以发现后一种方式的代码更为简洁,可是,除了代码看起来舒服之外,它们之间是否还有别的差异?且听我一一道来:
- 我们都知道第一种实现方式所创建的对象实例并不是全局唯一的,每次对象表达式被执行都会创建一个新的对象实例;而第二种方式,只要这个lambda没有访问任何来自定义它的函数的变量,那么这个lambda对应的内部类实例就是全局唯一的。
- 让我们先看下面一个例子:
view.viewTreeObserver.addOnGlobalLayoutListener(object: ViewTreeObserver.OnGlobalLayoutListener() {
override fun nGlobalLayout() {
//do something...
view.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
}
上面的例子中,我们最后移除监听器的时候通过this
引用了匿名对象的实例,那么我们是否可以把上面的例子替换成下面的样子呢?
view.viewTreeObserver.addOnGlobalLayoutListener {
//do something...
view.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
答案是不可以,对于编译器来说,lambda只是一个代码块,而不是一个对象,所以也就不能把它当作对象来引用,那么它内部的this到底指向何处呢?它指向包围这个lambda的类。
以上便是我对SAM的理解,如有疏漏,还请各位大大指出 ^ _ ^