禅与计算机程序设计艺术程序员我爱编程

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 -> }

通过对比,我们可以发现后一种方式的代码更为简洁,可是,除了代码看起来舒服之外,它们之间是否还有别的差异?且听我一一道来:

  1. 我们都知道第一种实现方式所创建的对象实例并不是全局唯一的,每次对象表达式被执行都会创建一个新的对象实例;而第二种方式,只要这个lambda没有访问任何来自定义它的函数的变量,那么这个lambda对应的内部类实例就是全局唯一的。
  2. 让我们先看下面一个例子:
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的理解,如有疏漏,还请各位大大指出 ^ _ ^

上一篇 下一篇

猜你喜欢

热点阅读