<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 功能強大 支持多語言、二開方便! 廣告
                # 泛型 [TOC] **泛型是一種編譯時的安全檢測機制,它允許在定義類、接口、方法時使用類型參數,聲明的類型參數在使用時用具體的類型來替換**。 泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。在本章我們將對泛型進行詳細講解。 **參考文章**: [泛型](http://www.hmoore.net/alex_wsc/android_kotlin/1318308) ## 泛型定義 現實生活中,我們在整理物品時,會把各種各樣的物品放在一個收納盒中,如剪刀、火機、梳子、頭繩等,這個收納盒相當于是一個容器,該容器中可以放各種物品。如果有一個空的收納盒,想要知道收納盒中放什么物品,只有當收納盒中放了物品之后才會知道放的是什么物品。收納盒這個容器的概念與JDK系統中的List集合比較類似,List集合也是一個容器,這個容器中也可以放置各種數據類型,如String、Int、Object等。如果想要知道List集合中存放的是什么類型的對象,則必須在該集合存放完對象之后才能知道。 當創建一個空的List集合時,調用List集合中的add()方法,該方法中傳遞的參數是一個“某種類型”的對象,由于這個“某種類型”是一個不確定的類型,因此可以通過泛型來表示。泛型即“參數化類型”,就是將具體的類型變成參數化類型,在聲明一個泛型時,傳遞的是一個類型形參,在調用時傳遞的是一個類型實參。 * 當定義泛型時,泛型是在類型名之后、主構造函數之前用尖括號“<>”括起來的大寫字母類型參數。 * 當定義泛型類型變量時,可以完整地寫明類型參數,如果編譯器可以自動推斷類型參數,則可以省略類型參數。 ``` class ArrayList<E> ``` 上述代碼中**E表示某種類型,定義時是一個未知類型**,稱為**類型形參**。E這個類型類似一個參數,當創建ArrayList實例時,需要傳入具體的類型。具體示例代碼如下: ``` var list1 = arrayListOf<String>("aa","bb","cc") var list2 = arrayListOf<Long>(111,222,333) var list3 = arrayListOf<Int>(1,2) ``` 上述代碼中傳入的參數String、Long、Int都是類型實參。 接下來我們通過一個例子來了解可以省略的泛型類型參數,具體示例代碼如下: ``` class Box<T>(t: T) { var value = t } ``` 上述代碼中T表示泛型的類型參數,如果要創建這個類的實例,則需要提供具體的類型參數。具體示例代碼如下: ``` val box: Box<Int> = Box<Int>(1) ``` **如果類型參數可以推斷出來,則可以省略類型參數**。具體示例代碼如下: ``` val box = Box(1) //參數1 是Int 類型 ``` 由于傳遞到構造函數中的參數是1,這個參數是一個Int類型的參數,編譯器可以推斷出泛型的類型是Int類型,因此在創建類的實例時可以省略類型參數。 ## 泛型:類型安全的利刃 眾所周知,Java 1.5引入泛型。那么我們來思考一個問題,為什么Java一開始沒有引入泛型,而1.5版本卻引入泛型?先來看一個場景: ``` List stringList = new ArrayList(); stringList.add(new Double(2.0)); String str = (String)stringList.get(0); 執行結果: >>> java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String at javat.Rectangle.main(Rectangle.java:29) ``` 因為ArrayList底層是用一個Object類型的數組實現的,這種實現雖然能讓ArrayList變得更通用,但也會帶來弊端。比如上面例子中,我們不小心向原本應作為String類型的List中添加了一個Double類型的對象,理想的情況下編譯器應該能夠提示錯誤,但事實上這段代碼能編譯通過,在運行時卻會報錯。這是一個非常糟糕的體驗,我們真正需要的是在代碼編譯的時候就能發現錯誤,而不是讓錯誤的代碼發布到生產環境中。這便是泛型誕生的一個重要的原因。有了泛型后,我們可以這么做: ``` List<String> stringList = new ArrayList<String>(); stringList.add(new Double(2.0)); //編譯時報錯,add(java.lang.String)無法適配add (java.lang.Double) ``` 利用泛型代碼在編譯時期就能發現錯誤,防止在真正運行的時候出現ClassCastException。當然,泛型除了能幫助我們在編譯時期進行類型檢查外,還有很多其他好處,比如自動類型轉換。 繼續來看第一段代碼,在獲取List中的值的時候,我們進行了以下操作: ``` String str = (String)stringList.get(0); ``` 是不是感覺異常的煩瑣,明明知道里面存的是String類型的值,取值的時候還要進行類型強制轉換。但有了泛型之后,就可以利用下面這種方式實現: ``` List<String> stringList = new ArrayList<String>(); stringList.add("test"); String str = stringList.get(0); ``` 有了泛型之后,不僅在編譯的時候能進行類型檢查,在運行時還會自動進行類型轉換。而且通過引入泛型,增強上述功能的同時并沒有增加代碼的冗余性。比如我們無須為聲明一個類型安全的List而去創建StringList、DoubleList等類,只需在聲明List的同時指定參數類型即可。 總的來說,泛型有以下幾點優勢: * 類型檢查,能在編譯時就幫你檢查出錯誤; * 更加語義化,比如我們聲明一個`List<String>`,便可以知道里面存儲的是String對象,而不是其他對象; * 自動類型轉換,獲取數據時不需要進行類型強制轉換; * 能寫出更加通用化的代碼。 ## 如何在Kotlin中使用泛型 假設現在我們有一個需求,定義一個find方法,傳入一個對象,若列表中存在該對象,則返回該對象,不存在則返回空。由于原有的集合類不存在這個方法,所以可以定義一個新的集合類,同樣也要聲明泛型。我們可以這么做: ``` class SmartList<T> : ArrayList<T> () { fun find(t: T): T? { val index = super.indexOf(t) return if (index >= 0) super.get(index) else null } } fun main(args: Array<String>) { val smartList = SmartList<String>() smartList.add("one") println(smartList.find("one"))//輸出one println(smartList.find("two").isNullOrEmpty())//輸出true } ``` 發現,Kotlin定義泛型類的方式與我們在Java中所看到的類似。另外泛型類同樣還可以繼承另一個類,這樣我們就可以使用ArrayList中的屬性和方法了。 當然,除了定義一個新的泛型集合類外,我們還可以利用擴展函數來實現這種需求。由于擴展函數支持泛型的情況,所以我們可以這么做: ``` fun <T> ArrayList<T>.find(t: T): T? { val index = this.indexOf(t) return if (index >= 0) this.get(index) else null } fun main(args: Array<String>) { val arrayList = ArrayList<String>() arrayList.add("one") println(arrayList.find("one"))//輸出one println(arrayList.find("two").isNullOrEmpty())//輸出true } ``` 利用擴展函數這種方式也非常簡潔,所以,當你只是需要對一個集合擴展功能的時候,使用擴展函數非常合適。 ### 使用泛型時是否需要主動指定類型? 在Kotlin中,以下的方式不被允許: ``` val arrayList = ArrayList() ``` 而在Java中卻可以這么做,這主要是因為泛型是Java 1.5版本才引入的,而集合類在Java早期版本中就已經有了。各種系統中已經存在大量的類似代碼: ``` List list = new ArrayList(); ``` 所以,為了保證兼容老版本的代碼,Java允許聲明沒有具體類型參數的泛型類。而Kotlin是基于Java 6版本的,一開始就有泛型,不存在需要兼容老版本代碼的問題。所以,**當你聲明一個空列表時,Kotlin需要你顯式地聲明具體的類型參數。當然,因為Kotlin具有類型推導的能力,所以以下這種方式也是可行的**: ``` val arrayList = arrayListOf("one", "two") ``` 總的來說,使用泛型可以讓我們的代碼變得更加通用化,更加靈活。但有時過于通用靈活并不是一個好的選擇,比如現在我們創建一個類型,只允許添加指定類型的對象。接下來我們就來看看如何在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>

                              哎呀哎呀视频在线观看