Kotlin类委托和属性委托
kotlin类委托
使用kotlin类委托
kotlin的类委托主要是接口代理,类似Java中代理模式。委托机制:类A需要实现的操作委托给类B来实现。举个例子:假设有个人A需要打官司但是不会,于是委托给律师B来打官司,在这个过程中A委托了B,B代理A来打官司,委托代理成对出现,一般先有委托再有代理,这个过程也可以通过代码来实现:
1 | /** |
通过kotlin字节码反编译,可以很明显的看出其实现方式就是通过Java的代理模式来实现的:
1 | // 打官司接口 |
覆写委托类方法
有些时候在委托类实现的情况下,又需要自定义方法实现,在这种情况下可以通过覆写委托类方法来实现,具体如以下代码:
1 | class ExampleList<T> (val innerList : MutableCollection<T> = mutableListOf()) : MutableCollection<T> by innerList{ |
kotlin属性委托
定义一个被委托的类
与类委托类似,属性委托也是通过by
关键字来定义的,其格式为:var/val 变量 :Type by 委托类
,具体代码如下:
1 | /** |
注意:
对于只读属性,即val
定义的变量,它的委托类必须提供一个getValue函数,且函数用operator关键字修饰,getValue有两个参数:
thisRef
:根据以上运行结果,thisRef指的是当前调用对象(即属性所有者),其类型约束与调用对象一致或者是调用对象的超类型(子类型)property
:当前属性所持有者的反射,其类型约束为KProperty<*>
或者是KProperty<*>
的超类型(子类型)
对于可读写属性,即var
定义的变量,它的委托类除了提供getValue函数,还需要提供一个setValue函数,同样的,setValue函数也需要用operator关键字来修饰,setValue函数接收3个参数:
thisRef
:同getValue()
property
:同getValue()
new value
:提供给当前属性用来赋新值的参数,其类型与当前属性一致或其超类型(子类型)
通过字节码将其转为Java代码,查看属性委托其原理:
1 | public final class ProxyExample { |
标准委托
在kotlin标准库中也内置了很多工厂方法实现属性的委托。
延迟加载–Lazy()函数
延迟加载lazy()函数的用法,具体如下代码:
1 | class ExampleByLazy{ |
val example by lazy
中lazy
是标准库中的一个函数,该函数传入的参数是一个lambda
表达式,其返回值是lazy<T>
,即属性example
实际上是委托给了lazy<T>
类
1 | public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer) |
lazy
函数返回的是lazy<T>
泛型类,但是实际上返回的是SynchronizedLazyImpl<out T>
1 | private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable { |
1 | internal.InlineOnly . |
泛型类lazy<T>
实现了一个getValue
的扩展方法,这是被委托类必须要实现的一个方法,getValue
函数返回的是lazy<T>
中的value
属性值,SynchronizedLazyImpl<out T>
是lazy<T>
的具体实现类,因此实际返回的是SynchronizedLazyImpl<out T>
中的value
属性值,value
属性值最终返回的就是lambda
表达式返回的值
注意:
- 泛型类
lazy<T>
并没有实现setValue
的扩展函数,所以委托给lazy<T>
的属性只能够使用val
来声明而不能够使用var
声明 lazy
函数是懒加载函数,只有第一次调用时能够完整执行lambda
函数,之后调用都只是返回值
1 | class ExampleByLazy{ |
可观察属性Observable
顾名思义,Dalegates.obserable()就是可观察的属性,可以对属性变化进行观察和处理,Delegates.observable传入两个参数:
- initialValue:提供该属性的初始值
- onChange:提供一个含有三个参数的lambda表达式,用于观察属性变化后对属性变化的额外处理,三个参数分别是
property: KProperty<*>, oldValue: T, newValue: T
,分别代表被赋值的属性,旧值,新值
Delegates.observable使用:
1 | // Delegates.observable |
跟踪Delegates.observable代码实现,理解其具体实现过程:
1 | public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit): |
1 | public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> { |
observable
是单例类Delegates中
的一个方法,observable
方法返回了类ObservableProperty
,ObservableProperty
是一个抽象类,所以需要覆写afterChange
函数,afterChange
函数实际上就是传递进来的onChange
lambda表达式,因而demo中ExampleObservable
中value
属性实际上是被委托给了ObservableProperty
类,这样整个实现就一目了然了
集合map
kotlin为Map
实现了getValue
扩展函数,所以Map
可以作为属性委托类,使用如下:
1 | class ExampleMap(val map: Map<String,Any?>){ |
Delegates.NotNull
与Delegates.observable用法类似,不过Delegates,NotNull适用于那些无法在初始化阶段就确定属性值的场合。
1 | class ExampleNotNull(){ |
注意:使用Delegates.NotNull如果属性在赋值前访问会抛出异常
1 | Exception in thread "main" java.lang.IllegalStateException: Property notNullValue should be initialized before get. |