kotlin语言学习

内联扩展函数

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 propertiesicon-default.png?t=M666https://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"
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值