Kotlin学习笔记之属性和方法

属性的setter和getter方法

Kotlin中定义了一个类的属性后,可以不用写其settergetter方法,编译的时候编译器会自动为你生成。但是有时候我们需要对属性进行一下特殊操作,这时候就需要重写settergetter方法,那什么时候需要重写settergetter⽅法。

  • 重写setter方法时机:
    • 外部给我值时,需要做额外的处理
    • 捕获外部给值的时机
  • 重写getter方法时机:
    • 外部获取值时,需要做额外的处理
    • 捕获外部需要的时机
    • 懒加载

延迟初始化lateinit

lateinit var name: String

一个变量必须有值,但是定义时不知道给什么值,可以用lateinit修饰,后续再赋值。需要注意的是在使用前必须为其赋值。上面的代码是延迟初始化定义name变量。

委托

委托 == 代理,我们在Java中学过一钟设计模式为代理模式,在Kotlin中可以通过by关键词让编译器自动生成委托代码

interface DB{
    fun sava()
}

class SqlDB(): DB{
    override fun sava() {
        println("sava in SqlDB")
    }
}
class MySqlDB(): DB{
    override fun sava() {
        println("sava in MySqlDB")
    }
}
class OracleDB(): DB{
    override fun sava() {
        println("sava in OracleDB")
    }
}

class CreateDBAction(db: DB): DB by db

fun main(){
    CreateDBAction(SqlDB()).sava()
    CreateDBAction(MySqlDB()).sava()
    CreateDBAction(OracleDB()).sava()
}
/** 
 * sava in SqlDB
 * sava in MySqlDB
 * sava in OracleDB
 */

反编译后编译器将会生成完整的CreateDBAction

public final class CreateDBAction implements DB {
   // $FF: synthetic field
   private final DB $$delegate_0;

   public CreateDBAction(@NotNull DB db) {
      Intrinsics.checkNotNullParameter(db, "db");
      super();
      this.$$delegate_0 = db;
   }

   public void sava() {
      this.$$delegate_0.sava();
   }
}

懒加载委托

fun requestDownload(): String{
    println("requestDownload run ...")
    Thread.sleep(2000L) // 模拟下载延时
    return "下载成功"
}

val responseData: String by lazy { requestDownload() }

// 懒加载委托
fun main(){
    println("准备工作中")
    Thread.sleep(3000L)
    
    println("开始请求")
    println(responseData)   // 如果responseData没有值则会执行懒加载,否则直接打印responseData的值
    println(responseData)
    println(respomseData)
}

/**执行结果
 * 准备工作中
 * 开始请求
 * requestDownload run ...
 * 下载成功
 * 下载成功
 * 下载成功
 */

懒加载只会调用一次,只有被调用的时候才会被加载,在上面代码的含义为responseData变量只会被初始化一次,后面访问的是就是变量的值。

注意:by lazy只能修饰val变量,而lateinit只能修饰var变量。

委托属性

委托属性公用被委托属性的set和get方法,底层原理为编译器生成被委托属性的单例对象,通过该实例可以获取到被委托对象的set和get方法,当调用委托属性的set和get方法时就会通过该实例调用set和get方法,从而实现公用set和get效果。

用途:当一个应用已经上线,里面的一个变量名需要更改,但是又不希望对之前代码进行修改,则可以使用属性委托,重新定义一个变量来委托之前的属性

class Simple{
    // version 1.0
    var info: String = "OK"
    
    // version 2.0
    var successInfo: String by ::info
}

代码中的 var successInfo: String by ::info 这行,::info 是将 info 属性作为委托的成员引用。这意味着 successInfo 属性的读取和写入操作都会被委托给 info 属性。successInfo 属性的读取操作会委托给 info 属性的 getter 方法,而写入操作会委托给 info 属性的 setter 方法。通过这种方式,successInfo 属性可以方便地访问和操作 info 属性的值。

自定义委托

简单的自定义委托(依赖类)

class Owner {
    var name: String by Nicely()
}

class Nicely{
    private var str: String = "Default"
    operator fun getValue(owner: Owner, kProperty: KProperty<*>): String{
        println("get被调用了")
        return str
    }

    operator fun setValue(owner: Owner, kProperty: KProperty<*>, value: String){
        println("set被调用了")
        str = value
    }
}

fun main(){
    val owner = Owner()
    owner.name = "Nicely"
    println(owner.name)
}

/**运行结果
 * set被调用了
 * get被调用了
 * Default
 */

不依赖类(两种方式)

// 方式一
var result: String = "Default"
private operator fun String.getValue(
    thisRef: Any?,
    property: KProperty<*>
): String {
    return result
}
private operator fun String.setValue(
    any: Any?,
    property:KProperty<*>,
    value: String
) {
    result = value
}

// 方式二
var result: String = "Default"
operator fun String.provideDelegate(
    thisRef: Any?,
    property:KProperty<*>
) = object : ReadWriteProperty<Any?, String> {
        override fun getValue(thisRef: Any?, property: KProperty<*>): String {
            println("test getValue value:$result")
            return result
        }

        override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
            println("test setValue value:$value")
            result = value
        }
    }

提供委托

在自定义委托类StringDelegator的基础之上创建一个类SimpleDelegator实现动态选择委托类,SimpleDelegator类必须实现provideDelegate操作符重载,方法逻辑可以自己实现。

kProperty为反射获取的成员变量,根据反射获得的成员变量名的不同来调用不同的自定义委托对象。

注意:在方法中定义的变量无法进行属性委托,因为无法通过反射获取该临时变量。

class StringDelegator(private var str: String): ReadWriteProperty<Owner2, String>{
    override fun getValue(thisRef: Owner2, property: KProperty<*>): String {
        println("StringDelegator#getValue run...")
        return str
    }

    override fun setValue(thisRef: Owner2, property: KProperty<*>, value: String) {
        println("StringDelegator#setValue run...")
        str = value
    }
}

class SimpleDelegator {
    operator fun provideDelegate(
        owner2: Owner2,
        kProperty: KProperty<*>
    ): ReadWriteProperty<Owner2, String>{
        return if (kProperty.name.contains("name")){
            StringDelegator("Nicely")
        }else{
            StringDelegator("ChongQing")
        }
    }

}

class Owner2{
    var name: String by SimpleDelegator()
    var address: String by SimpleDelegator()
}

fun main(){
    val owner = Owner2()
    owner.name = "Tom"
    owner.address = "BeiBei"
    println(owner.name)
    println(owner.address)
}

/**执行结果
 * StringDelegator#setValue run...
 * StringDelegator#setValue run...
 * StringDelegator#getValue run...
 * Tom
 * StringDelegator#getValue run...
 * BeiBei
 */

用途

用途一:观察 新值 旧值

class Simple1 {
    var name: String by Delegates.observable("Test") {
            prop, old, new ->
        println("旧值:$old -> 新值:$new")
    }
}

fun main() {
    val simple1 = Simple1()
    simple1.name = "Update1"
    simple1.name = "Update2"
}
/** Output:
 * 旧值:Test -> 新值:Update1
 * 旧值:Update1 -> 新值:Update2
 */

用途二:观察 setValue 与 getValue

class Item {
    var info: String by object : ReadWriteProperty<Item, String> {
        override fun getValue(thisRef: Item, property: KProperty<*>): String {
            println("监听到,你在获取值")
            return ""
        }

        override fun setValue(thisRef: Item, property: KProperty<*>, value: String) {
            println("监听到,你在设置值 value:$value")
        }
    }
}

fun main() {
    val item = Item()
    item.info = "Derry"
    println(item.info)
}
/** Output:
 * 监听到,你在设置值 value:Derry
 * 监听到,你在获取值
 */
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容