首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

从Java到Kotlin(六)

扩展与委托

目录

1.扩展

1.1 扩展函数

1.2 扩展属性

1.3 扩展伴生对象

1.4 扩展的作用域

2.委托

2.1 类委托

2.2 委托属性

2.3 标准委托

1.扩展

在Kotlin中,允许对类进行扩展,不需要继承该类或使用像装饰者这样的任何类型的设计模式,通过一种特殊形式的声明,来实现具体实现某一具体功能。扩展函数是静态解析的,并未对原类增添函数或者属性,对类本身没有影响。

1.1扩展函数

声明一个扩展函数,我们需要用一个接收者类型也就是被扩展的类型来作为他的前缀。 下面代码为Kotlin原生集合类 MutableList添加一个 swap 函数:

上面代码用MutableList作为接受者类型,对其进行扩展,为其添加一个 swap 函数,当我们调用 swap 函数时,可以这样:

运行代码,得到结果

内部成员函数名与扩展函数名相同

如果扩展函数与内部成员函数冲突,如下所示:

运行代码,得到结果:

由上面例子可得,如果扩展函数的函数名跟内部成员函数的函数名冲突,会优先调用内部成员函数。

可空接收者

可以为可空的接收者类型定义扩展,如下所示:

运行代码,得到结果:

上面代码中,我们对可空的接受者定义扩展,检测调用者是否为null,如果为null,返回"null",如果不为null,返回Any.toString()

1.2扩展属性

扩展属性是对属性的扩展,如下所示:

运行代码,得到结果:

上面代码中对 mValue 进行了属性扩展,抵用了扩展属性实现了 setter 方法,对 mValue 进行赋值,再通过扩展属性实现了 getter 方法,获取到 mValue 的值。

1.3扩展伴生对象

除了扩展函数和扩展属性外,还可以对伴生对象进行扩展,代码如下:

运行代码,得到结果

1.4扩展的作用域

在不同包里进行扩展

上面的代码都是在同一个包里进行扩展,如果在不同包里要进行扩展,就要用import来导入资源了,如下所示:

在其他包中调用

运行代码,得到结果:

由上面例子可得,如果要在不用的包里进行扩展,要在调用处 import 扩展的资源。

扩展声明为成员

在一个类内部你可以为另一个类声明扩展,如下所示:

运行代码,得到结果:

扩展声明所在的类的实例称为 分发接收者,扩展方法调用所在的接收者类型的实例称为 扩展接收者 。对于分发接收者和扩展接收者的成员名字冲突的情况,扩展接收者优先。如果要引用分发接收者的成员,可以这样写:

运行代码,得到结果:

上面 User.print() 这个扩展函数中,用到了 限定的 this 语法来调用 User2 的

printUser() 函数。

扩展成员的继承

声明为成员的扩展可以声明为 open 并在子类中覆盖。这意味着这些函数的分发对于分发接收者类型是虚拟的,但对于扩展接收者类型是静态的。

运行代码,得到结果:

2.委托

在Kotlin中,如果有多个地方用到了相同的代码,可以用委托来处理。

2.1类委托

委托模式是实现继承一个很好的的替代方式,Kotlin支持委托模式,不用为了实现委托模式而编写样板代码。举个例子:

从上面代码可以看出,Derived 类通过使用 by 关键字将 Base 接口的 print 方法委托给对象 b ,如果不进行委托的话,则要 override Base 接口的 print 方法。

如果出现委托后仍然 override 的情况,编译器会使用你的 override 实现取代委托对象中的实现,如下所示:

2.2 委托属性

在实际应用中,有很多类的属性都拥有 getter 和 setter 函数,这些函数大部分都是相同的。Kotlin允许委托属性,把所有相同的 getter 和 setter 函数放到同一个委托类中,这样能大大减少冗余代码。举个例子:

User1和User2都有相同的 getter 和 setter 函数,把它们放到委托类中,如下:

运行代码,得到结果:

可以看到,User1 和 User2 都将 userName 委托给 Delegate ,在 Delegate 内完成 getter/setter 函数,去除了相同的代码。

2.3 标准委托

Kotlin标准库中提供了一些有用的委托函数:

延迟委托

可观察属性委托

Map委托

延迟委托

是接受一个 lambda 表达式作为参数,并返回一个 实例的函数,返回的实例作为一个委托,第一次调用 会执行已传递给 的 lambda 表达式并记录结果, 之后再调用 返回记录的结果。

运行代码,得到结果:

默认情况下,对于 lazy 属性的求值是同步锁的(synchronized):该值只在一个线程中计算,并且所有线程会看到相同的值。如果初始化委托的同步锁不是必需的,这样多个线程可以同时执行,那么将 LazyThreadSafetyMode.PUBLICATION 作为参数传递给 lazy() 函数。如下所示:

而如果你确定初始化将总是发生在单个线程,那么你可以使用 LazyThreadSafetyMode.NONE 模式, 它不会有任何线程安全的保证和相关的开销,如下所示:

可观察属性委托

实现可观察属性委托的函数是,当我们使用该委托函数时,可以观察属性的变化,如下所示:

运行代码,得到结果:

接收两个参数,第一个是初始值,第二个是修改时处理程序(handler)。 每当我们给属性赋值时会调用该处理程序,他有三个参数,第一个是被赋值的属性,第二个是旧值,第三个是新值。

如果想拦截属性的赋值操作,并且否决他的赋值操作,可以用取代 ,传递给的修改时处理程序会返回一个boolean类型,如果返回true,允许赋值,返回false则反之。如下所示:

运行代码,得到结果:

Map委托

Map委托是指用Map实例自身作为委托来实现委托属性,通常用于解析 JSON ,如下所示:

因为只有方法而没有方法,所以不能通过User对象设置值,这时可以把User的主构函数改为传入一个,并把属性委托给,如下所示:

总结

本篇文章简述了Kotlin中扩展和委托的使用方法。扩展和委托都是Kotlin自身支持并非常好用的,扩展能使代码更灵活,委托能实现代码重用。运用好他们能很好地加快编写代码的速度。

参考文献:

Kotlin语言中文站、《Kotlin程序开发入门精要》

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180301G04IU700?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券