
4.3 扩展函数
4.3.1 扩展函数的特性
扩展函数是形如类名.方法名()这样的形式。Kotlin允许开发者在不改变已有类的情况下,为某个类添加新的函数,这个特性叫作扩展函数。感觉很黑科技,其实在其他语言中,诸如C#、Swift都有这个特性。
1.扩展函数
举一个简单的例子,对Java的String类增加一个checkEmail()函数,它的用途是判断字符串是否为电子邮件的格式。

上面String的扩展函数等价于下面的工具方法checkEmail:

查看一下Kotlin Bytecode,如图4-2所示,可以发现扩展函数实质上就是一个工具方法,并不是对原先的类进行修改而添加一个新的方法。
2.扩展函数能否跟原先的函数重名
我们带着这样的疑惑,来看看下面的例子。

执行结果如下:
this is from test()
从执行结果可以看出,上述代码并没有调用扩展函数test(),依然调用的是当前类的test()。
查看一下Kotlin Bytecode,如图4-2所示,可以发现扩展函数实质上就是一个工具方法,并不是对原先的类进行修改添加的新方法。
所以,当扩展函数跟原先的函数重名,并且参数都相同时,扩展函数就会失效,调用的是原先类的函数。从安全性角度考虑,这样做也是有一定道理的,否则任何人都可以借助扩展函数的特性来“hack”原有的代码。

图4-2 扩展函数的字节码
3.扩展函数是否具有多态性
多态是同一个行为具有多种不同表现形式或形态的能力。多态性是对象多种表现形式的体现。
在Java中,父类引用指向子类对象,调用方法时会调用子类的实现,而不是父类的实现。那么Kotlin的扩展函数是否具有多态性呢?来看下面的例子:

执行结果如下:
this is from base this is from base
在executeFoo()方法中,无论传递的是父类base,还是子类child,最后执行的都是父类的扩展函数。因此,我们可以得出结论,扩展函数不具备多态性。
4.Java调用Kotlin的扩展函数
以笔者的Android工具库和扩展函数库为例,GitHub地址:https://github.com/fengzhizi715/SAF-Kotlin-Utils。
其中有一个类名为Context+Extension.kt,从类名上一眼就能看出它包含多个针对Context的扩展函数。例如:

如果要在Java中调用该函数,则可以这样使用:
Context_ExtensionKt.getAppVersion(mContext);
我们会发现末尾多了Kt的后缀。由于该Kotlin类名为Context+Extension.kt,比较特殊,才会出现上面带有“_”的结果。如果该Kotlin类名为ContextExtension.kt,则在Java中是这样使用的:
ContextExtensionKt.getAppVersion(mContext);
总结一下扩展函数的特性:
· 扩展函数本质上并不是对原先的类新增一个方法,它是以静态导入的方式来实现的。
· 扩展函数跟原先的函数重名,并且参数都一样时,扩展函数会失效,调用的依旧是原先的函数。
· 扩展函数不具备多态性。
· Java也能调用Kotlin的扩展函数,可以把它当成是一个工具类来使用。