Kotlin 修炼指南(三),如何在 Android-Studio 下进行 NDK 开发
简化下实际上就是下面的代码。
object Singleton {
fun xxx() {}}
反编译后看生成代码,这就是一个典型的饿汉式单例,借助静态代码块初始化的锁,初始化单例实例,从而实现单例效果。
public final class Singleton {public static final Singleton INSTANCE;
public final void xxx() {}
private Singleton() {}
static {Singleton var0 = new Singleton();INSTANCE = var0;}}
通过 object 代替匿名内部类
这是 object 的另一个比较常用的地方,也符合了 object 的语义,定义一个类,并生成该类的实例,也就是需要创建的匿名内部类。
viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {override fun onPageScrollStateChanged(state: Int) {}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {}
override fun onPageSelected(position: Int) {}});
companion object
由于 Kotlin 中没有静态函数,所以在 Kotlin 中,可以使用 companion object 替代 Java 中的 static 修饰。
编译器会自动生成了一个叫做 Companion 的静态内部类。
在 Java 中调用伴生对象,可以使用 User.Companion.isMale(1)
class User {
companion object {const val DEFAULT_USER_AGE = 30}
fun test(){}}
// later, accessed like you would a static variable:user.age = User.DEFAULT_USER_AGE
Kotlin 函数
在 Kotlin 的基础库中,系统提供了大量针对函数的优化,解决了很多在 Java 代码中写起来不太爽的地方。
显式参数
在 Java 中,当一个函数的参数值太多时,需要一个个对齐参数,虽然可以通过 IDE 的快捷提示等功能来展示,但始终用起来不太方便,而在 Kotlin 中,除了像 Java 中那样按顺序的传递参数外,还可以通过指定参数名的方式进行参数传递。
fun test(name: String, age: Int) {}
test(name = "xys", age = 18)
参数含义一目了然,提高了代码的可读性。
参数默认值
fun test(name: String = "xys", age: Int) {}
fun a() {test(age = 18)}
通过参数默认值,可以避免 Java 下大量参数下的重载函数,当某个参数可以使用默认值时,就不用显示的声明了,类似 Java 中的不同参数的重载函数。
在 Java、Kotlin 混编的时候,无法避免的会混合调用,可以通过 @JvmOverloads 注解,给 Java 代码生成重载的函数。
拓展函数
拓展函数可以说是 Kotlin 最为重要的黑魔法之一了,通过拓展函数,可以给一些系统类添加原本没有的函数,极大的提高了函数的可拓展性。
fun Activity.toast(msg: String) {Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()}
拓展属性
与拓展函数类似,拓展属性可以给现有属性拓展自定义的实现。
val String.lastChar: Charget() = get(length - 1)
拓展功能看上去比较神奇,但大家可以通过查看 Kotlin 生成的 class 代码,反编译成的 Java 代码来看它具体的实现方法。
对于扩展函数来说,转化为 Java 代码的时候,其实就是生成一个静态的函数,这个静态函数的第一个参数就是该类的实例对象,所以这样把类的实例传入函数以后,函数内部就可以访问到类的公有方法。
扩展属性也是类似,获取的扩展属性会生成为一个静态的 get 函数,同时这个静态函数的第一个参数就是该类的实例对象,设置的扩展属性会转化为一个静态的 set 函数,同时这个静态函数的第一个参数就是该类的实例对象。函数内部可以访问公有的方法和属性。
在了解了其实现原理后,可以发现,拓展函数一定是 static 的,且不能被 override,也不存在运行时类型,其类型在编译时就已经确定,同时扩展函数和扩展属性内只能访问到类的公有方法和属性,私有的和 protected 同样是不能访问的。
拓展函数和拓展属性只是 Kotlin 语法的障眼法,并没有实际的去修改一个类
嵌套函数
函数是 Kotlin 中的第一公民,所以函数可以出现在 Kotlin 中的任何一个地方,包括在一个函数中。
在一个函数中定义另一个函数,可以很好的将这个函数的使用限制在当前的外层函数中,避免对外暴露不必要的接口,同时还能避免重复的模板代码,例如下面这个例子。
class User(val id: Int, val name: String, val address: String, val email: String)
fun check(user: User) {if (user.name.isEmpty()) {throw IllegalArgumentException("Can't save user {user.id}: empty Name")}if (user.address.isEmpty()) {throw IllegalArgumentException("Can't save user {user.id}: empty Address")}if (user.email.isEmpty()) {throw IllegalArgumentException("Can't save user ${user.id}: empty Email")}// ...}
通过嵌套函数实现。
fun saveUser2(user: User) {fun validate(value: String, fildName: String) {if (value.isEmpty()) {throw IllegalArgumentException("Can't save user fildName")}}
validate(user.name, "Name")validate(user.address, "Address")validate(user.email, "Email")// ...}
工具类函数
由于在 Kotlin 中,函数可以脱离类而独立存在,所以这对于工具类函数来说,就非常方便了,不用再定义一个 ToolUtil 类,而可以直接写在文件中。
作用域函数
作用域函数在[Kotlin 修炼指南(一)](
)中已经有详细介绍了。
设计模式
设计模式最早是在面向对象编程的基础上提出来的编程范式,但是对于函数式编程来说,有很多定义都过于教条了,所以,现代式的编程语言,通过很多语法上的定义,就已经实现了很多种设计模式。
单例模式
前面已经提到了,通过 object class,就可以很轻松的实现一个线程安全的单例类。
静态工厂模式
借助运算符重载,可以很方便的实现静态工厂模式。
interface Car {val brand: String
companion object {operator fun invoke(type: CarType): Car {return when (type) {CarType.AUDI -> Audi()
CarType.BMW -> BMW()}}}}
通过重载了 invoke()函数,在调用 Car(CarType.BMW)的时候,就创建好了对应的工厂实例。
代理模式 策略模式
代理模式,或者说策略模式,都可以通过 Kotlin 中的类委托来实现。
interface BaseTTS {fun doTTS()}
class BaiDuTTS : BaseTTS {override fun doTTS() {print("BaiDu")}}
class TencentTTS : BaseTTS {override fun doTTS() {print("Tencent")}}
class TTSCategory(tts: BaseTTS) : BaseTTS by tts
fun doTest() {TTSCategory(BaiDuTTS()).doTTS()}
通过类委托,将 tts 的实现代理出来。
更进一步,可以通过匿名类的方式,直接创建代理类的实现。
interface BaseTTS {fun doTTS()}
class TTSCategory(tts: BaseTTS) : BaseTTS by tts {override fun doTTS() {print("Do tts")}}
而当策略中只有一个函数的时候,还可以进一步简化,把策略直接封装成 Lambda 表达式。
class TTSCategory(val strategy: () -> Unit) {fun doTTS() {strategy.invoke()}}
fun test() {TTSCategory { print("Do tts") }.doTTS()}
评论