内联扩展函数
Kotlin系列之let、with、run、apply、also函数的使用
kotlin操作符
Kotlin中 ?、!!、?:、:: 、->符号的简单说明
kotlin协程
Kotlin 协程实战进阶(二、进阶篇:协程的取消、异常处理、Channel、Flow)
kotlin委托
Kotlin by 关键字
Kotlin by属性委托
by关键字得作用是实现委托模式
kotlin中,委托主要用处有两类
? ? ? ? 1.类委托.
类似于接口继承和组合.在声明类时采用如下方式
class ClassA(
//接口B的实现类
val interB:InterfaceB,
//接口C的实现类
val interB:InterfaceC,
...
//自定义的属性
}:InterfaceB by interB,InterfaceC by interC{
...
}
//使用方法
classA().methodInterfaceB()
classA().methodInterfaceC()
//把kotlin代码反编译为java代码,发现实现原理,相当于编译器帮我们在ClassA内部实现了B和C接口的方法,并在接口方法内部,调用了by委托的实例的实现方法.
//例如
class ClassA implement InterfaceB,InterfaceC{
final InterfaceB interB;
final InterfaceC interC;
ClassA(InterfaceB interB,InterfaceC interC){
this.interB=interB;
this.interC=interC;
}
public void methodInterfaceB(){
interB.methodInterfaceB();
}
public void methodInterfaceC(){
interC.methodInterfaceC();
}
}
? ? ? ? 2.属性委托
相比于类委托,多用于解决多继承问题,用的比较少.属性委托用处更多.kotlin中经常使用的延迟加载by lazy{}方法就是kotlin提供的模板属性委托方法
//属性委托的格式
val/var <属性名>:<类型> by <表达式>
这里的表达式主要是指setValue/getValue表达式.在完整的格式中,点击ctrl+左键点击by就可以找到对应表达式的实现
下面分析下常用属性委托的实现
2.1 延迟加载 by lazy{}
单击by,找到如下实现
@kotlin.internal.InlineOnly
public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
(这里需要补充扩展函数的知识,kotlin中允许通过扩展函数,在其他文件中为指定的类,添加新的功能方法)
恰好lazy{}返回的就是一个lazy<T>对象
同时,发现lazy<T>实现的只有getValue方法,没有setValue方法,所以by lazy{}只支持val属性的初始化,得到了一个新的解释
2.2 利用map映射来缓存属性
用法如下
classA(
val map:Map<Any,String>
){
val name:String by map
val time:String by map
}
这里相当于是每次获取name/time的值,通过map的查询同名key获得对应的映射value
通过在编辑器中点击by,可以找到如下实现
//map只支持getValue
@kotlin.internal.InlineOnly
public inline operator fun <V, V1 : V> Map<in String, @Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1 =
@Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V1)
//mutableMap支持getValue/setValue方法
@kotlin.jvm.JvmName("getVar")
@kotlin.internal.InlineOnly
public inline operator fun <V, V1 : V> MutableMap<in String, out @Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1 =
@Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V1)
@kotlin.internal.InlineOnly
public inline operator fun <V> MutableMap<in String, in V>.setValue(thisRef: Any?, property: KProperty<*>, value: V) {
this.put(property.name, value)
}
2.3 kotlin提供的模板接口
经过2.1和2.2的学习,可以得知一个类要支持属性委托,需要支持属性的设置和获取方法
kotlin中提供了标准的接口,只要支持该接口,那么实现类就可以实现属性委托
//val属性的实现接口
public fun interface ReadOnlyProperty<in T, out V> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public operator fun getValue(thisRef: T, property: KProperty<*>): V
}
//var属性的实现接口
public interface ReadWriteProperty<in T, V> : ReadOnlyProperty<T, V> {
/**
* Returns the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @return the property value.
*/
public override operator fun getValue(thisRef: T, property: KProperty<*>): V
/**
* Sets the value of the property for the given object.
* @param thisRef the object for which the value is requested.
* @param property the metadata for the property.
* @param value the value to set.
*/
public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}
kotlin变量
kotlin中声明变量
/**
* kotlin声明
* var代表可变变量,可以重复赋值
* val代表final变量,只能赋值1次
* 默认public可以直接外部访问,实际上是通过get/set方法来访问(val只有get方法),反编译可以证实
* 增加private,编译器不会增加get/set方法,减少了冗余代码
* 可以通过其他方式,让val可以重复赋值
*/
var name:String="time"
name="date"
[java]
public String name="time"
setName("date")
val name:String="hello"
name="world"===>error:编译出错
[java]
public final String name="hello"
在kotlin中,可以通过Backing properties来使val属性可以重复赋值
参考kotlin文档:??Backing propertieshttps://kotlinlang.org/docs/properties.html#backing-properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
}
return _table ?: throw AssertionError("Set to null by another thread")
}
这样在访问table属性时,表现出val特性,只能使用,不能更改
通过修改私有的_table变量,又可以改变table属性,实现原理如下,又涉及到kotlin到java的反编译处理
//这个现象背后的实现原理是这样的
//var和val的定义格式如下
var <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
[<setter>]
val <propertyName>[: <PropertyType>] [= <property_initializer>]
[<getter>]
//[]内的属性是可选的
//property_initializer是初始化属性
//如果val的定义格式如下
val <propertyName>[: <PropertyType>]
[<getter>]
//缺失了初始化属性的情况下,kotlin编译器,会把val属性编译为一个final修饰的get方法,而不是final修饰的属性
//这样,final修饰方法只是限制了方法不能重写,而不会限制方法返回
[kotlin]
val name:String
get()="time"
[java]
public final getName(){
return "time"
}
|