<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      kotlin類與對(duì)象——>委托、委托屬性

      1.委托

        1.1 委托的實(shí)現(xiàn)

          委托模式已經(jīng)證明是實(shí)現(xiàn)繼承的一個(gè)很好的替代方式,而 Kotlin 可以零樣板代碼地原生支持它。 Derived 類可以通過(guò)將其所有公有成員都委托給指定對(duì)象來(lái)實(shí)現(xiàn)一個(gè)接口 Base :

      interface Base {
          fun print()
      }
      
      class BaseImpl(val x: Int) : Base {
          override fun print() {
              print(x)
          }
      }
      
      // by-子句表示 b 將會(huì)在 Derived 中內(nèi)部存儲(chǔ),并且編譯器將生成轉(zhuǎn)發(fā)給 b 的所有 Base 的方法。
      class Derived(b: Base) : Base by b
      
      fun main() {
          val b = BaseImpl(10) 
          Derived (b).print()
      }

        1.2 覆蓋由委托實(shí)現(xiàn)的接口成員

          覆蓋符合預(yù)期:編譯器會(huì)使用 override 覆蓋的實(shí)現(xiàn)而不是委托對(duì)象中的。如果將 override fun printMessage() { print("abc") } 添加到 Derived,那么當(dāng)調(diào)用 printMessage 時(shí)程序 會(huì)輸出“abc”而不是“10”:

      interface Base {
          fun printMessage()
          fun printMessageLine()
      }
      
      class BaseImpl(val x: Int) : Base {
          override fun printMessage() {
              print(x)
          }
      
          override fun printMessageLine() {
              println(x)
          }
      }
      
      class Derived(b: Base) : Base by b {
          override fun printMessage() {
              print("abc")
          }
      }
      
      fun main() {
          val b = BaseImpl(10) 
          Derived (b).printMessage()
          Derived (b).printMessageLine()
      }

          請(qǐng)注意,以這種方式重寫的成員不會(huì)在委托對(duì)象的成員中調(diào)用 ,委托對(duì)象的成員只能訪問(wèn)其自身對(duì)接口成員實(shí)現(xiàn)

      interface Base {
          val message: String
          fun print()
      }
      
      class BaseImpl(val x: Int) : Base {
          override val message = "BaseImpl: x = $x" override fun print() {
              println(message)
          }
      }
      
      class Derived(b: Base) : Base by b {
          // 在 b 的 `print` 實(shí)現(xiàn)中不會(huì)訪問(wèn)到這個(gè)屬性 
          override val message = "Message of Derived"
      }
      
      fun main() {
          val b = BaseImpl(10)
          val derived = Derived(b) 
          derived.print() 
          println (derived.message)
      }

          注意:在 JVM 平臺(tái):當(dāng)使用帶有 default 方法的接口(包括帶有 @JvmDefault 注解的 Kotlin 接口)進(jìn)行委托時(shí),即使實(shí)際的委托類型提供了其自身的實(shí)現(xiàn)也會(huì)調(diào)用默認(rèn)實(shí)現(xiàn)。詳細(xì)信息請(qǐng)參 ?在 Java 中調(diào)用 Kotlin。

      2.委托屬性

        有一些常?的屬性類型,雖然我們可以在每次需要的時(shí)候手動(dòng)實(shí)現(xiàn)它們,但是如果能夠?yàn)榇蠹野阉麄冎?實(shí)現(xiàn)一次并放入一個(gè)庫(kù)會(huì)更好。例如包括:

      — 延遲屬性(lazyproperties):其值只在首次訪問(wèn)時(shí)計(jì)算;
      — 可觀察屬性(observableproperties):監(jiān)聽(tīng)器會(huì)收到有關(guān)此屬性變更的通知; 
      — 把多個(gè)屬性儲(chǔ)存在一個(gè)映射(map)中,而不是每個(gè)存在單獨(dú)的字段中。

        為了涵蓋這些(以及其他)情況,Kotlin 支持委托屬性:

      class Example {
          var p: String by Delegate()
      }
      語(yǔ)法是:val/var <屬性名>: <類型> by <表達(dá)式>。在by后面的表達(dá)式是該委托,因?yàn)閷傩詫?duì)應(yīng) 的 get()(與 set())會(huì)被委托給它的 getValue() 與 setValue() 方法。屬性的委托不必實(shí)現(xiàn) 任何的接口,但是需要提供一個(gè) getValue() 函數(shù)(與 setValue() ?對(duì)于 var 屬性)

        例如:

      import kotlin.reflect.KProperty
      
      class 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.")
          }
      }

        當(dāng)我們從委托到一個(gè) Delegate 實(shí)例的 p 讀取時(shí),將調(diào)用 Delegate 中的 getValue() 函數(shù),所 以它第一個(gè)參數(shù)是讀出 p 的對(duì)象、第二個(gè)參數(shù)保存了對(duì) p 自身的描述(例如你可以取它的名字)。例如

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

      輸出結(jié)果:
      Example@33a17727, thank you for delegating ‘p’ to me!

        類似地,當(dāng)我們給 p 賦值時(shí),將調(diào)用 setValue() 函數(shù)。前兩個(gè)參數(shù)相同,第三個(gè)參數(shù)保存將要被賦予的值

      e.p = "NEW"
      
      輸出結(jié)果:
      NEW has been assigned to ‘p’ in Example@33a17727.

        自 Kotlin 1.1 起你可以在函數(shù)或代碼塊中聲明一個(gè)委托屬性,因此它不一定是類的成員

      3.標(biāo)準(zhǔn)委托,Kotlin 標(biāo)準(zhǔn)庫(kù)為幾種有用的委托提供了工廠方法。

      4.延遲屬性 Lazy

        lazy() 是接受一個(gè) lambda 并返回一個(gè) Lazy <T> 實(shí)例的函數(shù),返回的實(shí)例可以作為實(shí)現(xiàn)延遲屬性 的委托:第一次調(diào)用 get() 會(huì)執(zhí)行已傳遞給 lazy() 的 lambda 表達(dá)式并記錄結(jié)果,后續(xù)調(diào)用get() 只是返回記錄的結(jié)果。

      val lazyValue: String by lazy {
          println("computed!")
          "Hello"
      }
      
      fun main() {
          println(lazyValue) 
          println (lazyValue)//只輸出Hello
      }

        默認(rèn)情況下,對(duì)于 lazy 屬性的求值是同步鎖的(synchronized):該值只在一個(gè)線程中計(jì)算,并且所有 線程會(huì)看到相同的值。如果初始化委托的同步鎖不是必需的,這樣多個(gè)線程可以同時(shí)執(zhí)行,那么將

        LazyThreadSafetyMode.PUBLICATION 作為參數(shù)傳遞給 lazy() 函數(shù)。而如果你確定初始化將 總是發(fā)生在與屬性使用位于相同的線程,那么可以使用 LazyThreadSafetyMode.NONE 模式:它不 會(huì)有任何線程安全的保證以及相關(guān)的開(kāi)銷。

      5.可觀察屬性 Observable

        Delegates.observable() 接受兩個(gè)參數(shù):初始值與修改時(shí)處理程序(handler)。每當(dāng)我們給屬性賦 值時(shí)會(huì)調(diào)用該處理程序(在賦值后執(zhí)行)。它有三個(gè)參數(shù):被賦值的屬性、舊值與新值

      import kotlin.properties.Delegates
      class User {
          var name: String by Delegates.observable("<no name>") {
              prop, old, new ->
              println("$old -> $new")
          }
      }
      fun main() {
          val user = User()
          user.name = "first"
          user.name = "second"
      }
      //如果你想截獲賦值并“否決”它們,那么使用 vetoable() 取代observable() 。在屬性被賦新值生 效之前會(huì)調(diào)用傳遞給 vetoable 的處理程序

      6.把屬性儲(chǔ)存在映射中

        一個(gè)常?的用例是在一個(gè)映射(map)里存儲(chǔ)屬性的值。這經(jīng)常出現(xiàn)在像解析JSON或者做其他“ 動(dòng)態(tài)”事情的應(yīng)用中。在這種情況下,你可以使用映射實(shí)例自身作為委托來(lái)實(shí)現(xiàn)委托屬性

      class User(val map: Map<String, Any?>) {
          val name: String by map
          val age: Int by map
      }

      在這個(gè)例子中,構(gòu)造函數(shù)接受一個(gè)映射參數(shù):

       val user = User(mapOf(
                  "name" to "John Doe",
                  "age" to 25
       ))

      委托屬性會(huì)從這個(gè)映射中取值(通過(guò)字符串鍵?屬性的名稱):

      println(user.name) // Prints "John Doe" 
      println(user.age) // Prints 25

      這也適用于 var 屬性,如果把只讀的 Map 換成 MutableMap 的話:

      class MutableUser(val map: MutableMap<String, Any?>) {
          var name: String by map
          var age: Int by map
      }

      7.局部委托屬性(自1.1起)

        你可以將局部變量聲明為委托屬性。例如,你可以使一個(gè)局部變量惰性初始化

      fun example(computeFoo: () -> Foo) {
          val memoizedFoo by lazy(computeFoo)
          if (someCondition && memoizedFoo.isValid()) {
              memoizedFoo.doSomething()
          }
      }

      //
      memoizedFoo變量只會(huì)在第一次訪問(wèn)時(shí)計(jì)算。如果someCondition失敗,那么該變量根本不會(huì)計(jì)算。

      8.屬性委托要求

        這里我們總結(jié)了委托對(duì)象的要求。

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

      //— thisRef ? 必須與 屬性所有者 類型(對(duì)于擴(kuò)展屬性?指被擴(kuò)展的類型)相同或者是其超類型。
      //— property ? 必須是類型 KProperty<*> 或其超類型。
      //getValue() 必須返回與屬性相同的類型(或其子類型)。
      
      class Resource
      class Owner {
          val valResource: Resource by ResourceDelegate()
      }
      
      class ResourceDelegate {
          operator fun getValue(thisRef: Owner, property: KProperty<*>): Resource {
              return Resource()
          }
      }

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

      //— thisRef ? 必須與 屬性所有者 類型(對(duì)于擴(kuò)展屬性?指被擴(kuò)展的類型)相同或者是其超類型。
      //— property ? 必須是類型 KProperty<*> 或其超類型。
      //— value — 必須與屬性類型相同(或者是其超類型)。
      
      class Resource
      class 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() 函數(shù)可以通過(guò)委托類的成員函數(shù)提供或者由擴(kuò)展函數(shù)提供。當(dāng)你 需要委托屬性到原本未提供的這些函數(shù)的對(duì)象時(shí)后者會(huì)更便利。兩函數(shù)都需要用 operator 關(guān)鍵字來(lái)進(jìn)行標(biāo)記

        8.3 委托類可以實(shí)現(xiàn)包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty 接口 之一。這倆接口是在 Kotlin 標(biāo)準(zhǔn)庫(kù)中聲明的:

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

       

      9.翻譯規(guī)則

        在每個(gè)委托屬性的實(shí)現(xiàn)的背后,Kotlin編譯器都會(huì)生成輔助屬性并委托給它。例如,對(duì)于屬性 prop,生 成隱藏屬性 prop$delegate,而訪問(wèn)器的代碼只是簡(jiǎn)單地委托給這個(gè)附加屬性

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

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

        請(qǐng)注意,直接在代碼中引用綁定的可調(diào)用引用的語(yǔ)法 this::prop 自 Kotlin 1.1 起才可用。

      10. 提供委托(自1.1 起)

        通過(guò)定義 provideDelegate 操作符,可以擴(kuò)展創(chuàng)建屬性實(shí)現(xiàn)所委托對(duì)象的邏輯。如果 by 右側(cè)所使 用的對(duì)象將 provideDelegate 定義為成員或擴(kuò)展函數(shù),那么會(huì)調(diào)用該函數(shù)來(lái)創(chuàng)建屬性委托實(shí)例。

        provideDelegate 的一個(gè)可能的使用場(chǎng)景是在創(chuàng)建屬性時(shí)(而不僅在其 getter 或 setter 中)檢測(cè)屬 性一致性。  

        例如,如果要在綁定之前檢測(cè)屬性名稱,可以這樣寫:

      class ResourceDelegate<T> : ReadOnlyProperty<MyUI, T> {
          override fun getValue(thisRef: MyUI, property: KProperty<*>): T {
              ...
          }
      }
      
      class ResourceLoader<T>(id: ResourceID<T>) {
          operator fun provideDelegate(
                  thisRef: MyUI,
                  prop: KProperty<*>
          ): ReadOnlyProperty<MyUI, T> {
              checkProperty(thisRef, prop.name)
              // 創(chuàng)建委托
              return ResourceDelegate()
          }
      
          private fun checkProperty(thisRef: MyUI, name: String) {
              ......
          }
      }
      
      class MyUI {
          fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> {
              ......
          }
      
          val image by bindResource(ResourceID.image_id)
          val text by bindResource(ResourceID.text_id)
      }
      //provideDelegate 的參數(shù)與 getValue 相同:
      //— thisRef —— 必須與 屬性所有者 類型(對(duì)于擴(kuò)展屬性?指被擴(kuò)展的類型)相同或者是它的超類 型;
      //— property —— 必須是類型 KProperty<*> 或其超類型。
      //在創(chuàng)建 MyUI 實(shí)例期間,為每個(gè)屬性調(diào)用 provideDelegate 方法,并立即執(zhí)行必要的驗(yàn)證

        如果沒(méi)有這種攔截屬性與其委托之間的綁定的能力,為了實(shí)現(xiàn)相同的功能,你必須顯式傳遞屬性名,這不是很方便:

      // 檢測(cè)屬性名稱而不使用“provideDelegate”功能 
      class MyUI {
          val image by bindResource(ResourceID.image_id, "image")
          val text by bindResource(ResourceID.text_id, "text")
      }
      
      fun <T> MyUI.bindResource(
              id: ResourceID<T>,
              propertyName: String
      ): ReadOnlyProperty<MyUI, T> {
          checkProperty(this, propertyName) 
          // 創(chuàng)建委托
      }

        在生成的代碼中,會(huì)調(diào)用 provideDelegate 方法來(lái)初始化輔助的 prop$delegate 屬性。比較對(duì) 于屬性聲明 val prop: Type by MyDelegate() 生成的代碼與上面(當(dāng) provideDelegate 方 法不存在時(shí))生成的代碼

      class C {
          var prop: Type by MyDelegate()
      }
      // 這段代碼是當(dāng)“provideDelegate”功能可用時(shí)
      // 由編譯器生成的代碼:
      class C {
          // 調(diào)用“provideDelegate”來(lái)創(chuàng)建額外的“delegate”屬性
          private val prop$delegate = MyDelegate().provideDelegate(this, this::prop)
          var prop: Type
              get() = prop$delegate.getValue(this, this::prop)
              set(value: Type) = prop$delegate.setValue(this, this::prop, value)
          //請(qǐng)注意,provideDelegate 方法只影響輔助屬性的創(chuàng)建,并不會(huì)影響為getter或setter生成的代碼。
      }

       

       

        

      posted @ 2020-06-30 15:45  王世楨  閱讀(550)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 中文字幕在线亚洲精品| 久久精品人妻无码专区| 成人午夜激情在线观看| 国产成人久久蜜一区二区| 亚洲第一香蕉视频啪啪爽| av色蜜桃一区二区三区| 丝袜a∨在线一区二区三区不卡| 国产一区二区三区怡红院| 日本无人区一区二区三区| 久久午夜无码免费| 无码AV无码免费一区二区| 国产成AV人片在线观看天堂无码| 肇庆市| 大色综合色综合网站| 亚洲欧美牲交| 亚洲一区av在线观看| 少妇人妻真实偷人精品| 国产成人一区二区三区免费| 日韩一区国产二区欧美三区| 热久久这里只有精品国产| 狠狠色狠狠色综合久久蜜芽| 特黄aaaaaaa片免费视频| 国产精品午夜无码AV天美传媒 | 精品国产精品午夜福利| 中文字幕av高清片| 亚洲成片在线看一区二区| 国产精品大全中文字幕| 吉木乃县| 国产在线观看91精品亚瑟| 久久无码中文字幕免费影院| 99精品热在线在线观看视 | 美女又黄又免费的视频| 2018年亚洲欧美在线v| 日韩成人性视频在线观看| 精品国产三级在线观看| 国产精品中文字幕日韩| 亚洲视频一区| 亚洲码欧洲码一二三四五| 国产成人一区二区视频免费| 国内久久人妻风流av免费 | 国产农村妇女高潮大叫|