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

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

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

      kotlin類與對象——>對象表達式與對象聲明、內聯類

      1.對象表達式與對象聲明

        有時候,我們需要創建一個對某個類做了輕微改動的類的對象,而不用為之顯式聲明新的子類。Kotlin 用對象表達式和對象聲明處理這種情況

      2.對象表達式

        要創建一個繼承自某個(或某些)類型的匿名類的對象,我們會這么寫:

      window.addMouseListener(object : MouseAdapter() {
          override fun mouseClicked(e: MouseEvent) { /*......*/
          }
      
          override fun mouseEntered(e: MouseEvent) { /*......*/
          }
      })

        如果超類型有一個構造函數,則必須傳遞適當的構造函數參數給它。多個超類型可以由跟在冒號后面的 逗號分隔的列表指定:

      open class A(x: Int) {
          public open val y: Int = x
      }
      
      interface B { /*......*/ }
      
      val ab: A = object : A(1), B {
          override val y = 15
      }

        任何時候,如果我們只需要“一個對象而已”,并不需要特殊超類型,那么我們可以簡單地寫

      fun foo() {
          val adHoc = object {
              var x: Int = 0
              var y: Int = 0
          }
          print(adHoc.x + adHoc.y)
      }

         請注意,匿名對象可以用作只在本地和私有作用域中聲明的類型。如果你使用匿名對象作為公有函數 的返回類型或者用作公有屬性的類型,那么該函數或屬性的實際類型會是匿名對象聲明的超類型,如果 你沒有聲明任何超類型,就會是 Any 。在匿名對象中添加的成員將無法訪問。

      class C {
          // 私有函數,所以其返回類型是匿名對象類型 
          private fun foo() = object {
              val x: String = "x"
          }
      
          // 公有函數,所以其返回類型是 Any
          fun publicFoo() = object {
              val x: String = "x"
          }
      
          fun bar() {
              val x1 = foo().x // 沒問題
              val x2 = publicFoo().x // 錯誤:未能解析的引用“x”
          }
      }

        對象表達式中的代碼可以訪問來自包含它的作用域的變量

      fun countClicks(window: JComponent) {
          var clickCount = 0
          var enterCount = 0
          window.addMouseListener(object : MouseAdapter() {
              override fun mouseClicked(e: MouseEvent) {
                  clickCount++
              }
      
              override fun mouseEntered(e: MouseEvent) {
                  enterCount++
              }
          })
      // ......
      }

      2.對象聲明

        單例模式在一些場景中很有用,而 Kotlin(繼 Scala 之后)使單例聲明變得很容易:

      object DataProviderManager {
          fun registerDataProvider(provider: DataProvider) {
              // ......
          }
      
          val allDataProviders: Collection<DataProvider>
              get() = // ......
      }

        這稱為對象聲明。并且它總是在 object 關鍵字后跟一個名稱。就像變量聲明一樣,對象聲明不是一個 表達式,不能用在賦值語句的右邊。

        對象聲明的初始化過程是線程安全的并且在首次訪問時進行。 如需引用該對象,我們直接使用其名稱即可:

      DataProviderManager.registerDataProvider(......)

        這些對象可以有超類型:

      object DefaultListener : MouseAdapter() {
          override fun mouseClicked(e: MouseEvent) {
              ......
          }
      
          override fun mouseEntered(e: MouseEvent) {
              ......
          }
      }

        注意:對象聲明不能在局部作用域(即直接嵌套在函數內部),但是它們可以嵌套到其他對象聲明或非內 部類中。

      3.伴生對象

        類內部的對象聲明可以用 companion 關鍵字標記:

      class MyClass {
          companion object Factory {
              fun create(): MyClass = MyClass()
          }
      }

        該伴生對象的成員可通過只使用類名作為限定符來調用:

      val instance = MyClass.create()

        可以省略伴生對象的名稱,在這種情況下將使用名稱 Companion :

      class MyClass {
          companion object {}
      }
      
      val x = MyClass.Companion

        其自身所用的類的名稱(不是另一個名稱的限定符)可用作對該類的伴生對象(無論是否具名)的引用:

      class MyClass1 {
          companion object Named {}
      }
      
      val x = MyClass1
      
      class MyClass2 {
          companion object {}
      }
      
      val y = MyClass2

        請注意,即使伴生對象的成員看起來像其他語言的靜態成員,在運行時他們仍然是真實對象的實例成 員,而且,例如還可以實現接口

      interface Factory<T> {
          fun create(): T
      }
      
      class MyClass {
          companion object : Factory<MyClass> {
              override fun create(): MyClass = MyClass()
          }
      }
      
      val f: Factory<MyClass> = MyClass

        當然,在 JVM 平臺,如果使用 @JvmStatic 注解,你可以將伴生對象的成員生成為真正的靜態方法和 字段。更詳細信息請參?Java 互操作性一節 。

      4.對象表達式和對象聲明之間的語義差異

      對象表達式和對象聲明之間有一個重要的語義差別:
      — 對象表達式是在使用他們的地方立即執行(及初始化)的;
      — 對象聲明是在第一次被訪問到時延遲初始化的;
      — 伴生對象的初始化是在相應的類被加載(解析)時,與Java靜態初始化器的語義相匹配。

      5.類型別名:

        類型別名為現有類型提供替代名稱。如果類型名稱太?,你可以另外引入較短的名稱,并使用新的名稱 替代原類型名。

        它有助于縮短較?的泛型類型。

        5.1 例如,通常縮減集合類型是很有吸引力的:

      typealias NodeSet = Set<Network.Node>
      typealias FileTable<K> = MutableMap<K, MutableList<File>>

        5.2 你可以為函數類型提供另外的別名

      typealias MyHandler = (Int, String, Any) -> Unit
      typealias Predicate<T> = (T) -> Boolean

        5.3 你可以為內部類和嵌套類創建新名稱:

      class A {
          inner class Inner
      }
      
      class B {
          inner class Inner
      }
      typealias AInner = A.Inner
      typealias BInner = B.Inner

        5.4 類型別名不會引入新類型。它們等效于相應的底層類型。當你在代碼中添加 typealias Predicate<T> 并使用 Predicate<Int> 時,Kotlin 編譯器總是把它擴展為 (Int) -> Boolean 。因此,當你需要泛型函數類型時,你可以傳遞該類型的變量,反之亦然:

      typealias Predicate<T> = (T) -> Boolean
      
      fun foo(p: Predicate<Int>) = p(42)
      
      fun main() {
          
          val f: (Int) -> Boolean = { it > 0 }
          println (foo(f)) // 輸出 "true"
          val p: Predicate<Int> = { it > 0 }
          println(listOf(1, -2).filter(p)) // 輸出 "[1]"
      
      }

      6.內聯類:內聯類僅在 Kotlin 1.3 之后版本可用,目前還是實驗性的

        有時候,業務邏輯需要圍繞某種類型創建包裝器。然而,由于額外的堆內存分配問題,它會引入運行時的 性能開銷。此外,如果被包裝的類型是原生類型,性能的損失是很糟糕的,因為原生類型通常在運行時就 進行了大量優化,然而他們的包裝器卻沒有得到任何特殊的處理。

        為了解決這類問題,Kotlin 引入了一種被稱為 內聯類 的特殊類,它通過在類的前面定義一個 inline 修飾符來聲明:

      inline class Password(val value: String)

        內聯類必須含有唯一的一個屬性在主構造函數中初始化。在運行時,將使用這個唯一屬性來表示內聯類的實例

      // 不存在 'Password' 類的真實實例對象
      // 在運行時,'securePassword' 僅僅包含 'String'
      val securePassword = Password("Don't try this in production")

        這就是內聯類的主要特性,它靈感來源于“inline”這個名稱:類的數據被“內聯”到該類使用的地方(類 似于內聯函數中的代碼被內聯到該函數調用的地方)

      7.成員

        內聯類支持普通類中的一些功能。特別是,內聯類可以聲明屬性與函數:

      inline class Name(val s: String) {
          val length: Int
              get() = s.length
      
          fun greet() {
              println("Hello, $s")
          }
      }
      
      fun main() {
          val name = Name("Kotlin")
          name.greet() // `greet` 方法會作為一個靜態方法被調用 
          println(name.length) // 屬性的 get 方法會作為一個靜態方法被調用
      }

        當然,內聯類的成員也有一些限制:

      — 內聯類不能含有init代碼塊
      — 內聯類不能含有幕后字段
          — 因此,內聯類只能含有簡單的計算屬性(不能含有延遲初始化/委托屬性)

      8.繼承

        內聯類允許去繼承接口

      interface Printable {
          fun prettyPrint(): String
      }
      
      inline class Name(val s: String) : Printable {
          override fun prettyPrint(): String = "Let's $s!"
      }
      
      fun main() {
          val name = Name("Kotlin")
          println(name.prettyPrint()) // 仍然會作為一個靜態方法被調用
      }

        禁止內聯類參與到類的繼承關系結構中。這就意味著內聯類不能繼承其他的類而且必須是 final

      9.表示方式

        在生成的代碼中,Kotlin 編譯器為每個內聯類保留一個包裝器。內聯類的實例可以在運行時表示為包裝 器或者基礎類型。這就類似于 Int 可以表示為原生類型 int 或者包裝器 Integer 。

        為了生成性能最優的代碼,Kotlin 編譯更傾向于使用基礎類型而不是包裝器。然而,有時候使用包裝器 是必要的。一般來說,只要將內聯類用作另一種類型,它們就會被裝箱。

      interface I
      inline class Foo(val i: Int) : I
      
      fun asInline(f: Foo) {}
      fun <T> asGeneric(x: T) {}
      fun asInterface(i: I) {}
      fun asNullable(i: Foo?) {}
      
      fun <T> id(x: T): T = x
      
      fun main() {
          val f = Foo(42)
          asInline(f) // 拆箱操作: 用作 Foo 本身
          asGeneric(f) // 裝箱操作: 用作泛型類型 T
          asInterface(f) // 裝箱操作: 用作類型 I
          asNullable(f) // 裝箱操作: 用作不同于 Foo 的可空類型 Foo?
      // 在下面這里例子中,'f' 首先會被裝箱(當它作為參數傳遞給 'id' 函數時)然后又被拆箱(當它從'id'函數 中被返回時)
      // 最后, 'c' 中就包含了被拆箱后的內部表達(也就是 '42'), 和 'f' 一樣
          val c = id(f)
      }

        因為內聯類既可以表示為基礎類型有可以表示為包裝器,引用相等對于內聯類而言毫無意義,因此這也 是被禁止的。

      10.名字修飾

        由于內聯類被編譯為其基礎類型,因此可能會導致各種模糊的錯誤,例如意想不到的平臺簽名沖突:

      inline class UInt(val x: Int)
      
      // 在 JVM 平臺上被表示為'public final void compute(int x)'
      fun compute(x: Int) { }
      
      // 同理,在 JVM 平臺上也被表示為'public final void compute(int x)'!
      fun compute(x: UInt) { }

        為了緩解這種問題,一般會通過在函數名后面拼接一些穩定的哈希碼來重命名函數。

      compute(x: UInt) 
      //將會被表示為
       public final void compute-<hashcode>(int x) 
      //以 此來解決沖突的問題。
      //請注意在 Java 中 - 是一個 無效的 符號,也就是說在 Java 中不能調用使用內聯類作為形參的函數

      11.內聯類和類標別名

        初看起來,內聯類似乎與類型別名非常相似。實際上,兩者似乎都引入了一種新的類型,并且都在運行時表示為基礎類型。

        然而,關鍵的區別在于類型別名與其基礎類型(以及具有相同基礎類型的其他類型別名)是 賦值兼容 的,而內聯類卻不是這樣。

        換句話說,內聯類引入了一個真實的新類型,與類型別名正好相反,類型別名僅僅是為現有的類型取了個新的替代名稱(別名)

      typealias NameTypeAlias = String
      
      inline class NameInlineClass(val s: String)
      
      fun acceptString(s: String) {}
      fun acceptNameTypeAlias(n: NameTypeAlias) {}
      fun acceptNameInlineClass(p: NameInlineClass) {}
      fun main() {
          val nameAlias: NameTypeAlias = ""
          val nameInlineClass: NameInlineClass = NameInlineClass("")
          val string: String = ""
          acceptString(nameAlias) // 正確: 傳遞別名類型的實參替代函數中基礎類型的形參 
          acceptString(nameInlineClass) // 錯誤: 不能傳遞內聯類的實參替代函數中基礎類型的形參
          // And vice versa:
          acceptNameTypeAlias(string) // 正確: 傳遞基礎類型的實參替代函數中別名類型的形參
          acceptNameInlineClass(string) // 錯誤: 不能傳遞基礎類型的實參替代函數中內聯類類型的形參
      }

      12.內聯類的實驗性狀態

        內聯類的設計目前是實驗性的,這就是說此特性是正在 快速變化的,并且不保證其兼容性。在 Kotlin 1.3+ 中使用內聯類時,將會得到一個警告,來表明此特性還是實驗性的。

      如需移除警告,必須通過指定編譯器參數 -Xinline-classes 來選擇使用這項實驗性的特性。

      13.在 Gradle 中啟用內聯類

      compileKotlin {
          kotlinOptions.freeCompilerArgs += ["-Xinline-classes"]
      }
      
      tasks.withType<KotlinCompile> { 
          kotlinOptions.freeCompilerArgs += "-Xinline-classes"
      }

      14.在 Maven 中啟用內聯類

      <configuration>
          <args>
              <arg>-Xinline-classes</arg> 
          </args>
      </configuration>

       

      posted @ 2020-06-30 14:18  王世楨  閱讀(450)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 精品国产一区二区三区av性色| 国产精品免费久久久免费| 日韩伦理片| 桃花岛亚洲成在人线AV| 国产欧美精品一区aⅴ影院| 亚洲精品男男一区二区| 欧美激欧美啪啪片| 日本公与熄乱理在线播放| 平罗县| 日本中文字幕乱码免费| 国产成人精品国产成人亚洲| japanese无码中文字幕| 亚洲av日韩av综合在线观看| 先锋影音男人av资源| 国产一区二区四区不卡| 久久国产精品成人免费| 黄男女激情一区二区三区| 国产精品色内内在线播放| 国产欧美日韩高清在线不卡| 久久精品国产亚洲av麻豆小说| 人妻中文字幕一区二区三| 最新精品国偷自产在线美女足| 扒开粉嫩的小缝隙喷白浆视频| 青青在线视频一区二区三区| 国产精品va在线观看无码不卡| 亚洲精品一二三四区| 色综合久久一区二区三区| 无码国模国产在线观看免费| √天堂中文www官网在线| 国产精品无码专区| 亚洲AV成人无码精品电影在线| 欧美性群另类交| 麻豆久久久9性大片| 午夜福利看片在线观看| 国产明星精品无码AV换脸| 视频一区二区 国产视频| 精品久久久中文字幕人妻| 国偷自产一区二区三区在线视频| 国产国产人免费人成免费| 欧美 日韩 国产 成人 在线观看| 中文字幕日韩有码一区|