日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Kotlin by属性委托

發布時間:2024/9/30 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Kotlin by属性委托 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/119939781
本文出自【趙彥軍的博客】

文章目錄

  • 屬性委托要求
  • 委托原理
  • 實戰演練,SharedPreference 委托
  • 升級之旅 ReadWriteProperty
  • 延遲委托 Lazy

在 Kotlin 中,通過 by 實現屬性委托,屬性委托 是什么意思呢?
簡單來說,就是屬性的 set、get 的操作,交給另一個對象器完成。

舉個例子:

class Example {var p: String by Delegate() }

語法是: val/var <屬性名>: <類型> by <表達式>。在 by 后面的表達式是該 委托, 因為屬性對應的 get()(與 set())會被委托給它的 getValue() 與 setValue() 方法。 屬性的委托不必實現任何的接口,但是需要提供一個 getValue() 函數(與 setValue()——對于 var 屬性)。 例如:

mport kotlin.reflect.KPropertyclass Delegate {operator fun getValue(thisRef: Any?, property: KProperty<*>): String {return "$thisRef, thank you for delegating '${property.name}' to me!"}operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {println("$value has been assigned to '${property.name}' in $thisRef.")} }

當我們從委托到一個 Delegate 實例的 p 讀取時,將調用 Delegate 中的 getValue() 函數, 所以它第一個參數是讀出 p 的對象、第二個參數保存了對 p 自身的描述 (例如你可以取它的名字)。 例如:

val e = Example() println(e.p)

輸出結果:

Example@33a17727, thank you for delegating ‘p’ to me!

類似地,當我們給 p 賦值時,將調用 setValue() 函數。前兩個參數相同,第三個參數保存將要被賦予的值:

e.p = "NEW"

輸出結果:

NEW has been assigned to ‘p’ in Example@33a17727.

屬性委托要求

對于一個只讀屬性(即 val 聲明的),委托必須提供一個操作符函數 getValue(),該函數具有以下參數:

  • thisRef —— 必須與 屬性所有者 類型(對于擴展屬性——指被擴展的類型)相同或者是其超類型。
  • property —— 必須是類型 KProperty<*> 或其超類型。

getValue() 必須返回與屬性相同的類型(或其子類型)。

class Resourceclass Owner {val valResource: Resource by ResourceDelegate() }class ResourceDelegate {operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {return Resource()} }

對于一個可變屬性(即 var 聲明的),委托必須額外提供一個操作符函數 setValue(), 該函數具有以下參數:

  • thisRef —— 必須與 屬性所有者 類型(對于擴展屬性——指被擴展的類型)相同或者是其超類型。
  • property —— 必須是類型 KProperty<*> 或其超類型。
  • value — 必須與屬性類型相同(或者是其超類型)。
class Resourceclass Owner {var varResource: Resource by ResourceDelegate() }class ResourceDelegate(private var resource: Resource = Resource()) {operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {return resource}operator fun setValue(thisRef: Owner, property: KProperty<*>, value: Any?) {if (value is Resource) {resource = value}} }

getValue() 或/與 setValue() 函數可以通過委托類的成員函數提供或者由擴展函數提供。 當你需要委托屬性到原本未提供的這些函數的對象時后者會更便利。 兩函數都需要用 operator 關鍵字來進行標記。

委托原理

在每個委托屬性的實現的背后,Kotlin 編譯器都會生成輔助屬性并委托給它。 例如,對于屬性 prop,生成隱藏屬性 prop$delegate,而訪問器的代碼只是簡單地委托給這個附加屬性:

class C {var prop: Type by MyDelegate() }// 這段是由編譯器生成的相應代碼: class C {private val prop$delegate = MyDelegate()var prop: Typeget() = prop$delegate.getValue(this, this::prop)set(value: Type) = prop$delegate.setValue(this, this::prop, value) }

簡單來說,委托之所以能實現,是因為kotlin 在編譯期間幫我們寫了代碼,動態的做了屬性的 set / get 方法

Kotlin 編譯器在參數中提供了關于 prop 的所有必要信息:第一個參數 this 引用到外部類 C 的實例而 this::prop 是 KProperty 類型的反射對象,該對象描述 prop 自身。

實戰演練,SharedPreference 委托

創建 UtilSharedPreference 委托類

/*** @author : zhaoyanjun* @time : 2021/8/25* @desc :*/ class UtilSharedPreference<T>(private val key: String, private val default: T) {operator fun setValue(thisRef: Any?, property: KProperty<*>, value: Any) {sp.edit().apply {when (value) {is Long -> putLong(key, value)is String -> putString(key, value)is Int -> putInt(key, value)is Boolean -> putBoolean(key, value)is Float -> putFloat(key, value)is Set<*> -> putStringSet(key, value as Set<String>) // only support Set<String>else -> throw IllegalArgumentException("SharedPreferences can't be save this type")}.apply()}}operator fun getValue(thisRef: Any?, property: KProperty<*>): T {sp.apply {val res: Any = when (default) {is Long -> getLong(key, default)is String -> getString(key, default) ?: ""is Int -> getInt(key, default)is Boolean -> getBoolean(key, default)is Float -> getFloat(key, default)is Set<*> -> getStringSet(key, default as Set<String>) ?: default as Set<String>else -> throw IllegalArgumentException("SharedPreferences can't be get this type")}return res as T}}companion object {lateinit var sp: SharedPreferencesfun initSharedPreference(context: Context, fileName: String) {sp = context.getSharedPreferences(fileName, Context.MODE_PRIVATE)}} }

使用如下:

class MainActivity : AppCompatActivity() {//委托var name: String by UtilSharedPreference("name", "")override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)//初始化UtilSharedPreference.initSharedPreference(this, "sp_file")//取值val newName = name//賦值name = "ppp"} }

到這里,我們已經實現了一個 SharedPreferences 方案了,運行了一下,非常完美。

在我查閱資料的時候,發現了一個大神的實現方式,地址是:

https://wazing.github.io/2019/05/23/kotlin-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%A7%94%E6%89%98%E6%96%B9%E5%BC%8F%E5%AE%9E%E7%8E%B0SharedPreferences/

下面貼一下代碼,寫的非常優秀。

object SharedPreferencesUtils {object User : Delegates() {override fun getSharedPreferencesName(): String = this.javaClass.simpleNamevar name by string()var phone by long()}abstract class Delegates {private val preferences: SharedPreferences by lazy {BaseApplication.instance.applicationContext.getSharedPreferences(getSharedPreferencesName(),Context.MODE_PRIVATE)}fun int(defaultValue: Int = 0) = object : ReadWriteProperty<Any, Int> {override fun getValue(thisRef: Any, property: KProperty<*>): Int {return preferences.getInt(property.name, defaultValue)}override fun setValue(thisRef: Any, property: KProperty<*>, value: Int) {preferences.edit().putInt(property.name, value).apply()}}fun string(defaultValue: String? = null) = object : ReadWriteProperty<Any, String?> {override fun getValue(thisRef: Any, property: KProperty<*>): String? {return preferences.getString(property.name, defaultValue)}override fun setValue(thisRef: Any, property: KProperty<*>, value: String?) {preferences.edit().putString(property.name, value).apply()}}fun long(defaultValue: Long = 0L) = object : ReadWriteProperty<Any, Long> {override fun getValue(thisRef: Any, property: KProperty<*>): Long {return preferences.getLong(property.name, defaultValue)}override fun setValue(thisRef: Any, property: KProperty<*>, value: Long) {preferences.edit().putLong(property.name, value).apply()}}fun boolean(defaultValue: Boolean = false) = object : ReadWriteProperty<Any, Boolean> {override fun getValue(thisRef: Any, property: KProperty<*>): Boolean {return preferences.getBoolean(property.name, defaultValue)}override fun setValue(thisRef: Any, property: KProperty<*>, value: Boolean) {preferences.edit().putBoolean(property.name, value).apply()}}fun float(defaultValue: Float = 0.0f) = object : ReadWriteProperty<Any, Float> {override fun getValue(thisRef: Any, property: KProperty<*>): Float {return preferences.getFloat(property.name, defaultValue)}override fun setValue(thisRef: Any, property: KProperty<*>, value: Float) {preferences.edit().putFloat(property.name, value).apply()}}fun setString(defaultValue: Set<String>? = null) = object :ReadWriteProperty<SharedPreferencesUtils, Set<String>?> {override fun getValue(thisRef: SharedPreferencesUtils, property: KProperty<*>): Set<String>? {return preferences.getStringSet(property.name, defaultValue)}override fun setValue(thisRef: SharedPreferencesUtils, property: KProperty<*>, value: Set<String>?) {preferences.edit().putStringSet(property.name, value).apply()}}fun clearAll() {preferences.edit().clear().apply()}abstract fun getSharedPreferencesName(): String} }

使用方式

// 該方式會存儲到SP中 SharedPreferencesUtils.User.name = "張無忌" SharedPreferencesUtils.User.phone = 18812345678 // 讀取 val name = SharedPreferencesUtils.User.name

升級之旅 ReadWriteProperty

在寫委托的時候,要寫 getValue 、setValue 方法,也是有點麻煩,好在系統已經內置了接口。

自定義的委托類可以實現包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty 接口之一。 這倆接口是在 Kotlin 標準庫中聲明的:

ublic interface ReadOnlyProperty<in R, out T> {public operator fun getValue(thisRef: R, property: KProperty<*>): T }public interface ReadWriteProperty<in R, T> {public operator fun getValue(thisRef: R, property: KProperty<*>): Tpublic operator fun setValue(thisRef: R, property: KProperty<*>, value: T) }

如果我們要實現自己的委托就可以直接實現 ReadOnlyProperty 、ReadWriteProperty 接口就行了。

舉例如下:

/*** @author : zhaoyanjun* @time : 2021/8/25* @desc : 自定義代理類*/ class MyUtil : ReadWriteProperty<Any, String> {override fun getValue(thisRef: Any, property: KProperty<*>): String {return ""}override fun setValue(thisRef: Any, property: KProperty<*>, value: String) {} }

延遲委托 Lazy

延遲委托是kotlin中最為常用的,lazy()后面接受lambda并返回一個lazy實例,返回的實例可以作為實現延遲屬性的委托:第一次調用 get() 會執行已傳遞給 lazy() 的 lamda 表達式并記錄結果, 后續調用 get() 只是返回記錄的結果。

private val str: String by lazy {println("(=?ω?=)")"hello world" }// 多次輸出 str 變量,只會輸出一次(=?ω?=),多次 hello world

原理如下

private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {private var initializer: (() -> T)? = initializer@Volatile private var _value: Any? = UNINITIALIZED_VALUE// final field is required to enable safe publication of constructed instanceprivate val lock = lock ?: thisoverride val value: Tget() {val _v1 = _valueif (_v1 !== UNINITIALIZED_VALUE) {@Suppress("UNCHECKED_CAST")return _v1 as T}return synchronized(lock) {val _v2 = _valueif (_v2 !== UNINITIALIZED_VALUE) {@Suppress("UNCHECKED_CAST") (_v2 as T)} else {val typedValue = initializer!!()_value = typedValueinitializer = nulltypedValue}}}override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUEoverride fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."private fun writeReplace(): Any = InitializedLazyImpl(value) }

總結

以上是生活随笔為你收集整理的Kotlin by属性委托的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。