属性委托深入详解

在上一次https://www.cnblogs.com/webor2006/p/11369019.html中学习了类委托,这次来学习一下属性的委托(delegated property),我们知道定义一个类的属性是需要给它一个初始值的,如果不给会报错,如下:

当然啦,可以加一个延迟属性来避免:

当然咱们不用这种方式,而是可以将此属性的赋值进行委托,目前该属性是可读可写,则在委托属性中需要定义可读可写的,而如果是用的val定义的属性则只需要定义可读的委托属性,具体如何做呢?下面先来定义一个委托类:

接下来需定义两个读写方法,注意:该方法的名称是有严格要求的,不能乱写方法名,下面来定义一下:

接下来则需要给它定义参数,第一个参数是要给哪个类进行委托,第二个参数是其委托的属性是哪一个,定义如下:

接下来再来定义setValue()方法,此时因为需要设置值,所以多了一个参数,其函数的参数大体跟getValue()差不多:

接下来则将这个委托关联到我们的属性上,如下:

下面咱们来调用一下:

从打印来看其值的读写确实是被委托了,其中特别要强调的是:

其中这里使用了运算符重载,貌似C++中也有这个关键字,如下:

那对于委托属性在实际开发中是有如下4种使用情况的:

1、延迟属性。

2、可观测属性。

3、非空属性。

4、map属性。

延迟属性:

这次先来对延迟属性和非空属性进行学习一下,先来看啥叫延迟属性:它指的是属性只有第一次被访问的时候才会计算,之后则会将之前的计算结果缓存起来供后续调用。下面看个具体例子:

下面来使用一下:

其中lazy是个函数,咱们来看一下它的声明:

好奇怪的写法,很显然咱们是将Lambda表达式写在了方法体中,而非方法参数中:

关于Kotlin的Lambda表达式跟Java8的Lambda表达式是不一样的,这个在之后会专门再学,这里之所以能写在方法体中是有这样一个规则:如果一个方法的最后一个参数是Lambda表达式,则直接可以将它写在方法体中。

另外lazy函数还有另外一个重载的版本,如下:

而该模式是被定义成了一个枚举类型:

所以咱们可以简单的使用一下这种重载的方法:

所以下面对这三种模式再总结一下:

1、SYNCHRONIZED:默认情况下,延迟属性的计算是同步的;值只会在一个线程中得到计算,所有的线程都会使用相同的一个结果。

2、PUBLICATION:如果不需要初始化委托的同步,这样多个线程可以同时执行。

3、NONE:如果确定初始化操作只会在一个线程中执行,这样会减少线程安全方面的开销。

非空属性

先来看一下代码:

我们知道对于定义的属性是必须要给它赋初值的,不然就报错了,但是如果没有一个合适的初值能赋给它,此时就可以将它委托给非空属性,如下:

其中看一下Delegated:

接着来看一下notNull()的说明:

其中它的实现是实例化了NotNullVar,如下:

而它的定义如下:

它实现了ReadWriteProperty这个接口,如下:

也就是系统对于委托的这俩函数已经定义好了,关于这个接口在未来还会学习的。好,接下来咱们来使用一下它:

那。。如果不赋值就直接读取呢?

确实如javadoc所说。所以notNull通常适用于那些无法在初始化阶段就确定属性值的场合。

posted on 2019-08-17 17:03  cexo  阅读(702)  评论(0编辑  收藏  举报

导航