Kotlin——高級篇(四):集合(Array、List、Set、Map)基礎

在實際的項目開發中,集合的運用能夠說是多不勝數。不過Kotlin中的集合運用和Java中仍是有很大的差異,他們二者之間,除了集合的類型相同之外,還包含集合的初始化的不一樣,以及Kotlin對於集合封裝特別多的高階函數以供咱們能更簡單、更快捷的編寫代碼。不過在講解集合以前,我先會對Kotlin中的數組類型作出一個講解,你們能夠當作是對數組Array<T>的一個溫故。git

目錄

1、數組類型

Kotlin數組類型不是集合中的一種,可是它又和集合有着太多類似的地方。而且數組和集合能夠互換。而且在初始化集合的時候也能夠傳入一個數組。用於數組類型在前面的章節已經講解過了,這裏就不在多作累述。有興趣的朋友能夠去看我前面關於數據類型的文章。
Kotlin——初級篇(三):數據類型詳解github

這裏只介紹幾個經常使用的方法。其實在文章的後面,也對這些方法作出了講解。數組

  • arr[index]的獲取元素。
  • arr.component1() ... arr.component5()獲取數組的前5個元素。一樣適用與集合。
  • arr.reverse()反轉元素。
  • 至於其餘處理的元素,在文章的尾部都有說明。這也是我把數組類型與集合類型放在同一文章講解的緣由。

例1:使用componentX()函數安全

val arr = arrayOf("1",2,3,4)

println(arr.component1())
println(arr.component3())

// 程序崩潰,由於元素只有4個,因此在不肯定元素個數的狀況,慎用這些函數,仍是使用遍歷安全些。
println(arr.component5())       
複製代碼

輸出結果:ide

1
3
複製代碼

例2 :反轉元素函數

val arr = arrayOf("1",2,3,4)
arr.reverse()

// 文章後面會講解forEach高階函數。比for循環簡潔多了
for (index in arr){
    print("$index \t")
}
複製代碼

輸出結果:post

4   3   2   1
複製代碼

2、集合類型

  • Kotlin中的集合和其餘語言不一樣的是,Kotlin集合可分爲可變和不可變集合。
  • Kotlin中,集合類型包含三種類型:它們分別是:ListSetMap,他們之間存在如下幾個異同點:
    1. 它們都是接口,並非實際的類。
    2. 它們只實現了isEmpty()、size、contains()等函數以及屬性。
    3. List<E>Set<E>都繼承至Collection<out E>接口,且Collection<out E>繼承於Iterable<out T>接口。而Map<K,V>是獨立出來的一個接口。這一點和Java相同。
    4. 這三種集合類型分別有存在MutableList<E>、MutableSet<E>、MutableMap<K,V>接口,這些接口中提供了改變、操做集合的方法。例如add()clear()remove()等函數。

有以上三點咱們可出,在定義集合類型變量的時候若是使用List<E>Set<E>Map<K,V>聲明的時候該集合則是不可變集合,而使用MutableList<E>MutableSet<E>MutableMap<K,V>的時候該集合纔是可變類型集合。這裏我就不提供源碼來分析了,有興趣的能夠看一看源碼!源碼在kotlin\collections\Collections.kt文件this

下面對幾個集合類型進行一一的講解。spa

2.一、List類型

咱們知道,一個接口是不能直接實例化的,那咱們要初始化一個怎麼作呢?其實Kotlin給咱們提供了相應的標準庫函數去處理。code

  • 聲明並初始化List的集合:使用listOf(..)函數
  • 聲明並初始化MutableList的集合:使用mutableListOf(..)函數

例1:使用listOf()初始化不可變的List類型集合

val arr = arrayOf("1","2",3,4,5)   
val list1 = listOf(1,2,"3",4,"5")                // 隨意建立         
val list2 = listOf<String>("1","2","3","4","5")  // 肯定元素的值類型
val list3 = listOf(arr)                          // 可傳入一個數組

如下代碼是錯誤的。由於List<E>只能是不可變集合。而add、remove、clear等函數時MutableList中的函數
list1.add() 
list1.remove
...

// 遍歷
for(value in list1){
    print("$value \t")
}
複製代碼

輸出結果:

1 	2 	3 	4 	5 
複製代碼

例2:使用mutableListOf()初始化可變的List類型集合

val arr = arrayOf("1",2,3,4)
val mutableList1 = mutableListOf(1,2,"3",4,"5")                // 隨意建立         
val mutableList2 = mutableListOf<String>("1","2","3","4","5")  // 肯定元素的值類型
val mutableList3 = mutableListOf(arr)                          // 可傳入一個數組
val mutableList : ArrayList<String>  // 這裏的ArrayList<>和Java裏面的ArrayList一致

mutableList1.add("6")  // 添加元素
mutableList1.add("7")
mutableList1.remove(1)   // 刪除某一元素

// 遍歷
for(value in mutableList1){
    print("$value \t")
}

mutableList1.clear()   // 清空集合
複製代碼

輸出結果爲:

2 	3 	4 	5 	6 	7 	
複製代碼

2.二、Set類型

Set類型集合的使用和List類型集合大體相同。這裏不作詳細的介紹,只講解它和List類型集合不一樣的地方。

  • 聲明並初始化Set的集合:使用setOf(..)函數
  • 聲明並初始化MutableSet的集合:使用mutableSetOf(..)函數

例1: 聲明並初始化

val set1 = setOf(1,2,"3","4","2",1,2,3,4,5)
val mutableSet1 = mutableSetOf(1,2,"3","4","2",1,2,3,4,5)
val mutableSet2 : HashSet<String>  // 這裏的HashSet<>和Java裏面的HashSet<>一致
複製代碼

例2 :遍歷集合,看效果與預計的有什麼不一樣

// 遍歷
for(value in set1){
    print("$value \t")
}
複製代碼

輸出結果:

1 	2 	3 	4 	2 	3 	4 	5 
複製代碼

在咱們預計的效果中,遍歷的結果應該爲:1 2 3 4 2 1 2 3 4 5,可是結果卻少了一個1 2。那麼咱們能夠看出,Set類型集合會把重複的元素去除掉。這一點和Java是不謀而合的。這個特性也是Set類型集合與List集合類型的區別所在。

2.三、Map類型

Map<K,V>類型集合和List以及Set都有着差異。下面咱們看Map類型集合的聲明及初始化。

同前面兩種類型同樣,Map一樣也分爲不可變與可變集合。其中:

  • 不可變的Map類型集合的初始化使用:mapOf()函數
  • 可變的Map類型集合的初始化使用:mutableMapOf()函數

不過初始化和前面兩種類型有差異,Map集合類型是一種以鍵-值對的方式出現。例:

// 以鍵值對的形式出現,鍵與值之間使用to
val map1 = mapOf("key1" to 2 , "key2" to 3)
val map2 = mapOf<Int,String>(1 to "value1" , 2 to "value2")
val mutableMap = mutableMapOf("key1" to 2 , "key1" to 3)
val hashMap = hashMapOf("key1" to 2 , "key1" to 3)   // 同Java中的HashMap

map2.forEach{
    key,value -> println("$key \t $value")
}
複製代碼

輸出結果爲:

1 	 value1
2 	 value2
複製代碼

注意:當咱們的鍵存在重複時,集合會過濾掉以前重複的元素

例:

val map = val map1 = mapOf("key1" to 2 , "key1" to 3 , "key1" to "value1" , "key2" to "value2")

map.forEach{
    key,value -> println("$key \t $value")
}
複製代碼

輸出結果爲:

key1 	 value1
key2 	 value2
複製代碼

從上面的例子能夠看出,當key值爲key1時,元素只保留了最後一個元素。而過濾掉了以前key值相同的全部元素。

3、 集合類型的協變

試想一下,當一個集合賦值給另一個集合時,這裏以List<E>舉例,若是兩個集合的類型也就是E類型相同時,賦值是沒有問題的。若是類型不一樣的狀況,當E繼承自M時。你就能夠把List<E>賦值給List<M>了。這種狀況稱之爲協變

我這裏舉兩個例子

例1:

open class Person(val name : String , val age : Int){
    override fun toString(): String {
        return "Person(name='$name', age=$age)"
    }
}

class Student(name: String, age : Int, cls : String) : Person(name, age)

// 注意:Any是kotlin中的超類,故而Student類也是繼承自Any的。這裏你能夠換成Person類結果是相同的
var listPerson: List<Any>
val listStudent : List<Student> = listOf(Student("張三",12,"一班"),Student("王五",20,"二班"))
listPerson = listStudent

listPerson.forEach { println(it.toString()) }
複製代碼

輸出結果:

Person(name='張三', age=12)
Person(name='王五', age=20)
複製代碼

例2:當集合的類型相同或有繼承關係時,一個集合使用MutableList,一個集合使用List的狀況。

var mutableListPerson: MutableList<Person>
val mutableListStudent : List<Student> = listOf(Student("張三",12,"一班"),Student("王五",20,"二班"))
mutableListPerson = mutableListStudent.toMutableList()
mutableListPerson.add(Person("a",15))
mutableListPerson.add(Person("b",45))

mutableListPerson.forEach { println(it.toString()) }
複製代碼

輸出結果爲:

Person(name='張三', age=12)
Person(name='王五', age=20)
Person(name='a', age=15)
Person(name='b', age=45)
複製代碼

看上面的實例2,使用了一個toMutableList()函數,其實這個函數的意思是把List轉換成了MutableList。在如下的源碼中咱們能夠看出:實際上是實例化了一個ArrayList

public fun <T> Collection<T>.toMutableList(): MutableList<T> {
    return ArrayList(this)
}

public fun <T> Iterable<T>.toMutableList(): MutableList<T> {
    if (this is Collection<T>)
        return this.toMutableList()
    return toCollection(ArrayList<T>())
}
複製代碼

SetMap集合的協變和上面的代碼都相差很少,調用不一樣的轉換函數罷了。除了toMutableList()函數之外,還有着toList()toHashSet()toSet()等等函數。這些函數都是在Iterable接口的拓展函數。你們有興趣能夠本身去看看源碼,這裏不作詳細的累述。

4、一些經常使用的處理集合類型的拓展函數

除了上面講到的toList()toSet()toHastSet()toMutableList()toSet()toIntArray()等等拓展函數以外。還有一些經常使用的拓展的高階函數。這裏列舉幾個說明。並實例分析他們的做用。全部的源碼都在kotlin\collections\_Collections.kt文件。

不過這裏因爲文章篇幅的緣由:這一節的內容會在下一章文章講解。

請參見Kotlin——高級篇(五):集合之經常使用操做符彙總

總結

在這篇文章中,詳細的講解到了集合的幾種類型的聲明與使用,而且也對數組類型Array<T>溫故了一遍。其實這篇文章的內容並非不少,你們主要記住集合類型初始化的幾個標準函數,以及集合的類型協變。在下一篇文章中會對處理集合與數組的常見函數作出一個講解以及源碼的剖析。

源代碼

在這最後但願您能給個關注,由於您的關注,是我繼續寫文章最好的動力。

個人我的博客Jetictors
GithubJteictors
個人掘金Jetictors

歡迎各位大佬進羣共同研究、探索

QQ羣號:497071402

相關文章
相關標籤/搜索