<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                Kotlin作為一門工程化的語言,擁有一些令開發者心曠神怡的特性。本章將帶領大家一步步了解Kotlin中一個比較重要的特性——擴展(Extensions)。Kotlin的擴展其實是多態的一種表現形式,在深入了解擴展之前,讓我們先探討一下多態的不同技術手段。 ## 多態的不同方式 熟悉Java的讀者對多態應該不會陌生,它是面向對象程序設計(OOP)的一個重要特征。當我們用一個子類繼承一個父類的時候,這就是子類型多態(Subtype polymorphism)。另一種熟悉的多態是參數多態(Parametric polymorphism),我們在后面所討論的泛型就是其最常見的形式。此外,也許你還會想到C++中的運算符重載,我們可以用特設多態(Ad-hoc polymorphism)來描述它。相比子類型多態和參數多態,可能你對特設多態會感到有些許陌生。其實這是一種更加靈活的多態技術,在Kotlin中,一些有趣的語言特性,如運算符重載、擴展都很好地支持這種多態。在本節接下來的內容中,我們將通過具體的例子來進一步展現各種多態的特點,并介紹更加深入的Kotlin語言特性。 ### 子類型多態 無論在前端、移動端還是后臺開發中,數據持久化操作都是必不可少的。在Android中,原生就支持Sqlite的操作,一般我們會繼承Sqlite操作的相關類: class CustomerDatabaseHelper(context:Context): SQLiteOpenHelper(context, "kotlinDemo.db", cursorFactory , db.version){ override fun onUpgrade(p0: SQLiteDatabase? , p1: Int, p2: Int) {} override fun onCreate(db: SQLiteDatabase) { val sql = "CREATE TABLE if not exists $tableName ( id integer PRIMARY KEY autoincrement, uniqueKey VARCHAR(32))" // 此處省略其他參數 db.execSQL(sql) } } 然后我們就可以使用父類DatabaseHelper的所有方法。這種用子類型替換超類型實例的行為,就是我們通常說的子類型多態。 ### 參數多態 在完成數據庫的創建之后,現在我們要把客戶(Customer)存入客戶端數據庫中。可能會寫這樣一個方法: ``` fun persist(customer: Customer) { db.save(customer.uniqueKey, customer) } ``` 如果代碼成功執行,我們就成功地將customer以鍵值對的方式存入數據庫(上述例子中以uniqueKey對應customer,便于查詢等操作)。 但是,隨著需求的變動,我們可能還會持久化多種類型的數據。如果每種類型都寫一個presist方法,多少有些煩瑣,通常我們會抽象一個方法來處理不同類型的持久化。因為我們采用鍵值對的方式存儲,所以需要獲取不同類型對應的uniqueKey: ``` interface KeyI { val uniqueKey : String } class ClassA(override val uniqueKey: String) : KeyI { … } class ClassB(override val uniqueKey: String) : KeyI { … } ``` 這樣,class A、B都已經具備uniqueKey。我們可以將persist進行如下改寫: ``` fun <T: KeyI> persist(t: T) { db.save(t.uniqueKey, t) } ``` 以上的多態形式我們可以稱之為參數多態,其實最常見的參數多態的形式就是泛型。 參數多態在程序設計語言與類型論中是指聲明與定義函數、復合類型、變量時不指定其具體的類型,而把這部分類型作為參數使用,使得該定義對各種具體類型都適用,所以它建立在運行時的參數基礎上,并且所有這些都是在不影響類型安全的前提下進行的。 ### 對第三方類進行擴展 進一步思考,假使當對應的業務類ClassA、ClassB是第三方引入的,且不可被修改時,如果我們要想給它們擴展一些方法,比如將對象轉化為Json,利用之前介紹的多態技術就會顯得比較麻煩。 幸運的是,Kotlin支持擴展的語法,利用擴展我們就能給ClassA、ClassB添加方法或屬性,從而換一種思路來解決上面的問題。 ``` fun ClassA.toJson(): String = { …… } ``` 如上我們給ClassA類擴展了一個將對象轉換為Json的toJson方法。需要注意的是,擴展屬性和方法的實現運行在ClassA實例,它們的定義操作并不會修改ClassA類本身。這樣就為我們帶來了一個很大的好處,即被擴展的第三方類免于被污染,從而避免了一些因父類修改而可能導致子類出錯的問題發生。 當然,在Java中我們可以依靠其他的辦法比如設計模式來解決,但相較而言依靠擴展的方案顯得更加方便且合理,這其實也是另一種被稱為特設多態的技術。下節我們就來了解下這種多態,然而再介紹Kotlin中另外一種同樣可服務于它的語言特性——運算符重載。 ### 特設多態與運算符重載 除了子類型多態、參數多態以外,還存在一種更靈活的多態形式——特設多態(Ad-hoc polymorphism)。可能你對特設多態這個概念并不是很了解,我們來舉一個具體的例子。 當你想定義一個通用的sum方法時,也許會在Kotlin中這么寫: ``` fun <T> sum(x: T, y: T) : T = x + y ``` 但編譯器會報錯,因為某些類型T的實例不一定支持加法操作,而且如果針對一些自定義類,我們更希望能夠實現各自定制化的“加法語義上的操作”。如果把參數多態做的事情打個比方:它提供了一個工具,只要一個東西能“切”,就用這個工具來切割它。然而,現實中不是所有的東西都能被切,而且材料也不一定相同。更加合理的方案是,你可以根據不同的原材料來選擇不同的工具來切它。 再換種思路,我們可以定義一個通用的Summable接口,然后讓需要支持加法操作的類來實現它的plusThat方法。就像這樣子: interface Sumable<T> { fun plusThat(that: T): T } data class Len(val v: Int) : Sumable<Len> { override fun plusThat(that: Len) = Len(this.v + that.v) } 可以發現,當我們在自定義一個支持plusThat方法的數據結構如Len時,這種做法并沒有什么問題。然而,如果我們要針對不可修改的第三方類擴展加法操作時,這種通過子類型多態的技術手段也會遇到問題。 于是,你又想到了Kotlin的擴展,我們要引出另一種叫作“特設多態”的技術了。相比更通用的參數多態,特設多態提供了“量身定制”的能力。參考它的定義,特設多態可以理解為:一個多態函數是有多個不同的實現,依賴于其實參而調用相應版本的函數。 針對以上的例子,我們完全可以采用擴展的語法來解決問題。此外,Kotlin原生支持了一種語言特性來很好地解決問題,這就是運算符重載。借助這種語法,我們可以完美地實現需求。代碼如下: data class Area(val value: Double) operator fun Area.plus(that: Area): Area { return Area(this.value + that.value) } fun main(args: Array<String>) { println(Area(1.0) + Area(2.0)) // 運行結果:Area(value=3.0) } 下面我們來具體介紹下Kotlin中運算符重載的語法。相信你已經注意到了operator關鍵字,以及Kotlin中內置可重載的運算符plus。先來看看operator,它的作用是:將一個函數標記為重載一個操作符或者實現一個約定。 注意,這里的plus是Kotlin規定的函數名。除了重載加法,我們還可以通過重載減法(minus)、乘法(times)、除法(div)、取余(mod)(Kotlin1.1版本開始被rem替代)等函數來實現重載運算符。此外,你可以再回憶一下第2章中遇到的一些基礎語法,它們也是利用這種神奇的語言特性來實現的,如: ``` a in b // 轉換為b.contains(a) f(a) // 轉換為f.invoke(a) ``` 我們將會展示如何利用Kotlin運算符重載的語法,來簡化經典的設計模式。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看