扩展方法可以在不修改或继承原类的情况下给原类添加方法,当然扩展方法并不是真正的添加进了原类。下面通过一个例子看看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对象,也就是我们常说的具体化泛型。