kotlin 扩展方法

扩展方法可以在不修改或继承原类的情况下给原类添加方法,当然扩展方法并不是真正的添加进了原类。下面通过一个例子看看kotlin是怎么处理的。

这里给Double添加了扩展方法,将double format成常见的金钱格式即:
10000->10,000

1
2
3
4
5
fun Double.format2Money(): String {
    val pattern = "###,###.##"
    val df = DecimalFormat(pattern)
    return df.format(this)
}

然后我们调用

1
val money = 10000.format2Money()

反编译成java看看。tools->Kotlin->Show Kotlin Bytecode,然后Decompile

1
2
3
4
5
6
7
8
9
10
public final class MoneyUtilsKt {
   @NotNull
   public static final String format2Money(double $receiver) {
      String pattern = "###,###.##";
      DecimalFormat df = new DecimalFormat(pattern);
      String var10000 = df.format($receiver);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "df.format(this)");
      return var10000;
   }
}

可以看到kotlin帮我们生成了一个静态方法,然后将调用者当做参数$receiver传进去=。=
和我们自己写的uitls也没啥分别嘛。虽然是糖,但是用起来舒服呀。而且阅读性较强,还可以配合系统封装好的几个高阶函数使用。比如给Activity添加一个弹框dialog扩展函数。

1
2
3
4
inline fun AppCompatActivity.showDialog(block: AlertDialog.Builder.() -> Unit) =
    AlertDialog.Builder(this).run {
        block(this)
    }

在Activity中就可以这样调用了

1
2
3
4
5
6
showDialog {
            setTitle("title")
            setMessage("message")
            setCancelable(false)
            show()
}

之前有分析过run函数,现在再来看看

1
2
3
public inline fun <T, R> T.run(block: T.() -> R): R {
    return block()
}

可以看到系统封装的这几个高阶函数是给T类型添加的扩展方法,所以任何对象都可以调用。那么我们也可以这样操作。

1
2
3
4
inline fun <T> T.showDialog(block: AlertDialog.Builder.() -> Unit) =
    AlertDialog.Builder(ActivityUtils.getTopActivity()).run {
        block(this)
    }

这样就可以任意地方调用了,当然这里只是示范,不建议这样写。可以添加通用性方法,log扩展函数。

1
inline fun <reified T> T.logD(msg:String) = Log.d(T::class.java.name, msg)

简单来说下关键字reified。reified修饰泛型后,可以通过T::class.java拿到class对象,也就是我们常说的具体化泛型。