Kotlin 对象、枚举、委托

一、Kotlin 对象

1. kotlin 伴生对象


class Demo {
    val field: String = "demo field"

    // kotlin 定义伴生对象
    companion object {
        // kotlin 定义常量
        const val KEY_NAME = "key_name"

        // kotlin 模拟静态方法 
        @JvmStatic // 加注解实现和 java 中使用静态方法相同效果
        fun method() {
            println("invoke companion method")
        }
    }
}


fun main() {
    // kotlin 可以使用外部类的类名直接调用伴生对象的属性或方法
    Demo.KEY_NAME
    Demo.method()
}

2. kotlin 对象和单例模式


fun main() {
    // 使用 object 声明对象表达式
    val runnable = object : Runnable {
        override fun run() {
            println("run in Runnable")
        }
    }
    // 同上,lambda 简写形式
    val runnable2 = Runnable {
        println("run in Runnable lambda")
    }

    // 使用对象表达式
    Thread(runnable).start()
    Thread(runnable2).start()

    // 调用单例类的属性和方法
    println(DemoManager.field)
    DemoManager.method()
}

/**
 * 使用 object 定义单例类
 */
object DemoManager {

    var field = "string value"

    fun method() {
        println("invoke method")
    }
}

二、Kotlin 枚举

1. kotlin 定义枚举


enum class Week(val text: String = "") {
    Monday("星期一"),
    Tuesday("星期二"),
    Wednesday("星期三"),
    Thursday("星期四"),
    Friday("星期五"),
    Saturday("星期六"),
    Sunday("星期日")
}

2. kotlin 使用枚举


fun main() {
    // 构造枚举
    val tuesday = Week.valueOf("Tuesday")

    // 访问枚举常量的名称,与在其枚举声明中声明的完全相同。
    println(tuesday.name) // Tuesday

    // 返回此枚举常量的序数(它在枚举声明中的位置,其中初始常量被分配零序数)
    println(tuesday.ordinal) // 1

    // 返回此枚举类型的常量的数组
    println(Week.values().contentToString()) // [Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday]

    // 访问枚举
    val week: Week = Week.Monday

    when (week) {
        Week.Monday -> println(week.name) // Monday
        Week.Tuesday -> println(week.name)
        Week.Wednesday -> println(week.name)
        Week.Thursday -> println(week.name)
        Week.Friday -> println(week.name)
        Week.Saturday -> println(week.name)
        Week.Sunday -> println(week.name)
    }
}

三、Kotlin 委托

1. kotlin 类委托


/**
 * 定义接口
 */
interface Factory {
    fun produce()
}

/**
 * 美食工厂,实现工厂的方法
 */
class FoodFactory : Factory {
    override fun produce() {
        println("生产美食")
    }
}


/**
 * Agent1 实现了 Factory 接口,但委托给 FoodFactory 去实现
 */
class Agent1(factory: FoodFactory) : Factory by factory

/**
 * Agent2 实现了 Factory 接口,但委托给 FoodFactory 去实现,重写了接口定义的方法
 */
class Agent2 : Factory by FoodFactory() {
    override fun produce() {
        println("Agent2 自己 生产美食")
    }
}

fun main() {
    // 类委托
    val agent1 = Agent1(FoodFactory())
    agent1.produce() // 生产美食
    val agent2 = Agent2()
    agent2.produce() // Agent2 自己 生产美食
}

2. kotlin 属性委托

提供和 ReadOnlyProperty 或 ReadWriteProperty 接口相同签名的方法即可实现属性委托


/**
 * 定义属性委托
 */
class FieldDemo {
    var name: String by FieldDelegate()
}

/**
 * 属性委托类,提供和 ReadOnlyProperty 或 ReadWriteProperty 接口相同签名的方法即可实现属性委托
 */
class FieldDelegate {
    private var fieldValue = "default str"

    operator fun getValue(thisRef: FieldDemo, property: KProperty<*>): String {
        println("获取 ${thisRef.javaClass.simpleName} 的属性 ${property.name} 值")
        return fieldValue
    }

    operator fun setValue(thisRef: FieldDemo, property: KProperty<*>, value: String) {
        println("设置 ${thisRef.javaClass.simpleName} 的属性 ${property.name} 值:$value")
        fieldValue = value
    }
}

fun main() {
    // 属性委托
    val fieldDemo = FieldDemo()
    fieldDemo.name = "test field delegate" // 设置 FieldDemo 的属性 name 值:test field delegate
    println(fieldDemo.name) // 获取 FieldDemo 的属性 name 值
}

3. kotlin Map 委托

  • kotlin 在 MapAccessors 类中给 Map 定义了和 ReadOnlyProperty 接口相同签名的方法,可以用于只读属性的委托。
  • kotlin 在 MapAccessors 类中给 MutableMap 定义了和 ReadWriteProperty 接口相同签名的方法,可以用于读写属性的委托。

/**
 * 只读属性可以委托给 Map
 * 类只需要对外暴露 map 即可
 */
class DelegateMap(val map: Map<String, Any?>) {
    val key1: Int by map
    val key2: String by map
    val key3: Boolean by map
}

/**
 * 读写属性可以委托给 MutableMap
 * 类只需要对外暴露 map 即可
 */
class DelegateMutableMap(val map: MutableMap<String, Any?>) {
    var key1: Int by map
    var key2: String by map
    var key3: Boolean by map
}

fun main() {
    // 只读属性对外暴露 Map
    val delegate1 = DelegateMap(mapOf("key1" to 1, "key2" to "str", "key3" to true))

    // 相当于调用 ReadOnlyProperty 的 getValue 方法
    println(delegate1.key1)
    println(delegate1.key2)
    println(delegate1.key3)

    val map = delegate1.map
    println(map["key1"])
    println(map["key2"])
    println(map["key3"])

    // 读写属性对外暴露 MutableMap
    val delegate2 = DelegateMutableMap(mutableMapOf())

    // 相当于调用 ReadWriteProperty 的 setValue 方法
    delegate2.key1 = 100
    delegate2.key2 = "key2 value"
    delegate2.key3 = false

    val mutableMap = delegate2.map
    println(mutableMap["key1"])
    println(mutableMap["key2"])
    println(mutableMap["key3"])
}

4. kotlin 延迟属性

  • 当延迟属性被访问的时候才会执行 lambda 表达式初始化值
  • 只会执行一次 lambda 表达式,随后会获取第一次的值直接返回

// 延迟属性:只会获取一次 lambda 表达式的值,后续会使用第一次获取的值直接返回
val lazyField: String by lazy {
    println("执行 lambda 表达式")
    "this is a lazy field"
}

// 传入策略,使用锁用于确保只有单个线程可以初始化Lazy实例。
val lazyField2: String by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
    "this is a lazy field"
}

fun main() {
    // 只会打印一次 "执行 lambda 表达式"
    println(lazyField)
    println(lazyField)
}

5. kotlin 属性监听


/**
 * 属性监听,总是能赋值成功
 */
var observerField1: String by Delegates.observable("default") { property, oldValue, newValue ->
    println("$property 的 oldValue: $oldValue, newValue: $newValue")
}

/**
 * 属性监听,符合条件 新值大于 0,才能成功赋值
 */
var observerField2: Int by Delegates.vetoable(0) { property, oldValue, newValue ->
    println("$property 的 oldValue: $oldValue, newValue: $newValue")
    newValue > 0
}

fun main() {
    observerField1 = "set new value" // 打印:kotlin.String 的 oldValue: default, newValue: set new value

    observerField2 = 1 // 打印:kotlin.Int 的 oldValue: 0, newValue: 1
    observerField2 = -1 // 打印:kotlin.Int 的 oldValue: 1, newValue: -1,此处会设置失败,需要大于0才能设置成功
    println(observerField2) // 打印:1
}

附 Github 源码

Companion&Object&Enum&Delegate&Lazy.kt

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>