[TOC]
### map集合介紹
相比于List、Set。Map 則提供了元素存儲的另外一種方式。Map 集合類用于存儲鍵值對(key-value),一個鍵(key)對應一個值(value),鍵(key)不能重復。
#### map應用場景
舉個例子,比如教室里面所有學生的姓名,我們用list集合存儲不用考慮太多,用set集合存儲就需要考慮班級同學名字是否有重復的,因為set會去重。
如果用map集合存儲,則需要考慮的更多,首先要考慮把名字做為key還是作為value。如果把名字作為key,那要考慮,班上同學名字是否有重復,有重復的就不能作為key,map集合key不能重復的。假如名字不重復,名字可以作為key,那繼續考慮,每個key對應的value是什么,比如可以是學生成績、身高等,map集合value可以重復。這樣,一個學生姓名可以找到一個學生成績、身高等數據。
如果把名字定為value,班上同學名字是否有重復則不重要,那你就要為每一個名字找一個唯一不重復的key,比如可以是學號,學號都是唯一的。這樣一個學號就可以找到一個學生。
從代碼角度去理解, map集合由Map接口和Map接口的實現類組成。
#### Map接口常用的實現類有哪些?
**HashMap、LinkedHashMap、TreeMap和MutableMap。**
* HashMap:基于Map接口哈希表實現,通過哈希表對其內部的映射關系快速查找,存取效率高,迭代無序。
* LinkedHashMap:基于Map接口哈希表實現和鏈接列表實現,鏈接列表定義了迭代順序,該迭代順序可以是插入順序或者是訪問順序。
* TreeMap:基于紅黑樹實現的,迭代根據其鍵的自然順序進行排序,或者可以自行指定比較器。
#### map集合可以存儲什么類型數據呢?
map集合可以存儲各種類型數據。可以存儲諸如Int、Double、String等基本數據類型,也可以存儲其他自定義對象類型,比如自定義的學生Student。
### map集合4種創建方式
在Kotlin中創建map集合有4種方式,4種方式可以分為兩類,一類是通過構造方法方法創建map集合。另外一種,是通過Kotlin給我們封裝好的方法創建map集合。如下表格,我們將這四種方式列舉了出來。
| 創建map集合方法 | 返回值類型 | 是否可寫|
| -------------------------- | ------------- | ------------ |
| hashMapOf()方法 | HashMap | 是 |
| mapOf方法 | Map | 否 |
| mutableMapOf ()方法 | MutableMap | 是 |
| TreeMap ()的構造方法 | TreeMap | 是 |
我們可以直接看4種方式的對應方法的方法簽名,重點看返回值,方法體的部分我直接去掉了,對應的源碼如下:
```
//方式一
public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> =
if (pairs.size > 0) pairs.toMap(LinkedHashMap(mapCapacity(pairs.size))) else emptyMap()
//方式二
public fun <K, V> hashMapOf(vararg pairs: Pair<K, V>): HashMap<K, V> = HashMap<K, V>(mapCapacity(pairs.size)).apply { putAll(pairs) }
//方式三
public fun <K, V> mutableMapOf(vararg pairs: Pair<K, V>): MutableMap<K, V> =
LinkedHashMap<K, V>(mapCapacity(pairs.size)).apply { putAll(pairs) }
//方式四
public TreeMap() {
comparator = null;
}
```
作為了解,可以通過翻看源碼得知4種創建集合方式上的細微差別,有的是通過Java里面的HashMap創建,有的是通過LinkedHashMap。這個意義不是很大。
更需要知道的是:返回Map不可寫,返回HashMap、MutableMap、TreeMap可寫。具體使用的時候,忘記是否可寫怎么辦?只需要點進去看看方法的返回值即可。或者,看每個方法的注釋,返回只讀的map集合,會出現**read-only map**字樣。比如查看mapof方法的定義,參考截圖:
~~~
/**
* Returns a new read-only map with the specified contents, given as a list of pairs
* where the first value is the key and the second is the value.
*
* If multiple pairs have the same key, the resulting map will contain the value from the last of those pairs.
*
* Entries of the map are iterated in the order they were specified.
*
* The returned map is serializable (JVM).
*
* @sample samples.collections.Maps.Instantiation.mapFromPairs
*/
public fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V> =
if (pairs.size > 0) pairs.toMap(LinkedHashMap(mapCapacity(pairs.size))) else emptyMap()
~~~
我們通過代碼演示集合的四種創建方式:
~~~
fun main(args: Array<String>) {
val map1 = mapOf<String, Int>(
Pair("佳佳", 168),
Pair("巧巧", 165),
Pair("依依", 170),
Pair("婷婷", 172),
Pair("貝貝", 163)
)
println(map1)
val map2 = hashMapOf<String, Int>(
Pair("佳佳", 168),
Pair("巧巧", 165),
Pair("依依", 170),
Pair("婷婷", 172),
Pair("貝貝", 163)
)
println(map2)
val map3 = mutableMapOf<String, Int>(
Pair("佳佳", 168),
Pair("巧巧", 165),
Pair("依依", 170),
Pair("婷婷", 172),
Pair("貝貝", 163)
)
println(map3)
val map4 = TreeMap<String, Int>()
map4.put("佳佳", 168)
map4.put("巧巧", 165)
map4.put("依依", 170)
map4.put("婷婷", 172)
map4.put("貝貝", 163)
println(map4)
}
~~~
運行結果
```
{佳佳=168, 巧巧=165, 依依=170, 婷婷=172, 貝貝=163}
{佳佳=168, 依依=170, 貝貝=163, 巧巧=165, 婷婷=172}
{佳佳=168, 巧巧=165, 依依=170, 婷婷=172, 貝貝=163}
{佳佳=168, 依依=170, 婷婷=172, 巧巧=165, 貝貝=163}
Process finished with exit code 0
```
針對上面的代碼。
* 第一,4種方式創建的時候,都指定了map集合中元素的類型。
* 第二,mapOf()、hashMapOf ()、mutableMapOf ()中包含的Pair類型的元素,**都是通過Pair的構造方法創建的。**
如果是通過mapOf()、hashMapOf ()、mutableMapOf ()三個方法創建map集合,而且調用方法的時候,又往map集合中傳入至少一個元素,那么編譯器是可以幫助我們完成map集合中元素類型的自動推斷的,參考代碼:
~~~
fun main(args: Array<String>) {
//沒有指定鍵值對類型,類型自動推斷
val map1 = mapOf(
Pair("佳佳", 168),
Pair("巧巧", 165),
Pair("依依", 170),
Pair("婷婷", 172),
Pair("貝貝", 163)
)
println(map1)
val map2 = hashMapOf(
Pair("佳佳", 168),
Pair("巧巧", 165),
Pair("依依", 170),
Pair("婷婷", 172),
Pair("貝貝", 163)
)
println(map2)
val map3 = mutableMapOf(
Pair("佳佳", 168),
Pair("巧巧", 165),
Pair("依依", 170),
Pair("婷婷", 172),
Pair("貝貝", 163)
)
println(map3)
}
~~~
運行結果
```
{佳佳=168, 巧巧=165, 依依=170, 婷婷=172, 貝貝=163}
{佳佳=168, 依依=170, 貝貝=163, 巧巧=165, 婷婷=172}
{佳佳=168, 巧巧=165, 依依=170, 婷婷=172, 貝貝=163}
Process finished with exit code 0
```
mapOf()、hashMapOf ()、mutableMapOf ()中包含的Pair類型的元素,**除了通過Pair的構造方法創建,還可以通過to方法**。我們看to方法的定義如下:
~~~
/**
* Creates a tuple of type [Pair] from this and [that].
*
* This can be useful for creating [Map] literals with less noise, for example:
* @sample samples.collections.Maps.Instantiation.mapFromPairs
*/
public infix fun <A, B> A.to(that: B): Pair<A, B> = Pair(this, that)
~~~
可以看到是一個帶infix關鍵字的中綴函數。所以,我們創建map的時候,還可以有如下的常用形式,參考代碼:
~~~
fun main(args: Array<String>) {
//不使用pair方法,使用to方法更形象
val map1 = mapOf(
"佳佳" to 168,
"巧巧" to 165,
"依依" to 170,
"婷婷" to 172,
"貝貝" to 163
)
println(map1)
val map2 = hashMapOf(
"佳佳" to 168,
"巧巧" to 165,
"依依" to 170,
"婷婷" to 172,
"貝貝" to 163
)
println(map2)
val map3 = mutableMapOf(
"佳佳" to 168,
"巧巧" to 165,
"依依" to 170,
"婷婷" to 172,
"貝貝" to 163
)
println(map3)
}
~~~
運行結果
```
{佳佳=168, 巧巧=165, 依依=170, 婷婷=172, 貝貝=163}
{佳佳=168, 依依=170, 貝貝=163, 巧巧=165, 婷婷=172}
{佳佳=168, 巧巧=165, 依依=170, 婷婷=172, 貝貝=163}
Process finished with exit code 0
```
### map集合可寫性驗證以及轉換
我們通過代碼驗證集合是否可寫,先驗證集合可寫,參考代碼:
~~~
fun main(args: Array<String>) {
val map = hashMapOf(Pair("佳佳", 168))
//寫入
map.put("玲玲", 172)
println(map)
val map2 = mutableMapOf<String, Int>(
"佳佳" to 1,
"依依" to 2)
//追加元素
map2.put("玲玲", 3)
println(map2)
}
~~~
運行結果
```
{佳佳=168, 玲玲=172}
{佳佳=1, 依依=2, 玲玲=3}
```
我們在驗證集合不可寫,參考代碼:
~~~
fun main(args: Array<String>) {
val map = mapOf<String, Int>(Pair("佳佳", 168))
//map.put("玲玲", 172)這里會報錯,無法編譯
println(map)
}
~~~
但是,不可寫集合可以通過toMutableMap轉換為可寫集合,然后在進行寫操作,參考代碼:
~~~
fun main(args: Array<String>) {
val map = mapOf<String, Int>(Pair("佳佳", 168))
println(map)
//轉換
val mutableMap = map.toMutableMap()
//添加
mutableMap.put("玲玲", 172)
println(mutableMap)
}
~~~
運行結果
```
{佳佳=168}
{佳佳=168, 玲玲=172}
Process finished with exit code 0
```
### map集合數據鍵key唯一,值value可重復
參考代碼:
~~~
fun main(args: Array<String>) {
val map = mutableMapOf<String, Int>(
"佳佳" to 1,
"依依" to 2)
//追加元素
map.put("小翠", 1)
println(map)
}
~~~
運行結果
```
{佳佳=1, 依依=2, 小翠=1}
```
### map集合遍歷操作
前面我們學習了區間的遍歷,數組的遍歷。那如何遍歷map集合呢?map集合的遍歷和數組的遍歷一樣。
也就是map集合在遍歷的時候,可以普通的for循環,還可以for循環的時候調用withIndex方法,參考代碼:
~~~
fun main(args: Array<String>) {
val map = mapOf<String, Int>(
"佳佳" to 168,
"巧巧" to 165,
"依依" to 170,
"婷婷" to 172
)
println("--------直接遍歷map--------")
for (entry in map) {
println("${entry.key}->${entry.value}")
}
println("--------遍歷map.entries--------")
for (entry in map.entries) {
println("${entry.key}->${entry.value}")
}
println("--------遍歷map的keys--------")
for (key in map.keys) {
println(key)
}
println("--------遍歷map的values--------")
for (value in map.values) {
println(value)
}
println("--------解構申明--------")
for ((key, value) in map) {
println("$key->$value")
}
}
~~~
運行結果
```
--------直接遍歷map--------
佳佳->168
巧巧->165
依依->170
婷婷->172
--------遍歷map.entries--------
佳佳->168
巧巧->165
依依->170
婷婷->172
--------遍歷map的keys--------
佳佳
巧巧
依依
婷婷
--------遍歷map的values--------
168
165
170
172
--------解構申明--------
佳佳->168
巧巧->165
依依->170
婷婷->172
Process finished with exit code 0
```
當然,還可以通過迭代器或者高階函數進行遍歷操作。
### map集合數據無序
同set集合,map集合同樣無序,應該怎么去理解呢?就是我們的Map接口,不保證加入和取出順序一致。但是子接口會做一些保證。
* HashMap內部存儲的時候會根據元素的hashCode排序,元素取出的時候無序。
* LinkedHashMap內部存儲的時候也會根據元素的hashCode排序,但是使用鏈表存儲,元素取出順序和插入順序一致。
* TreeMap 內部存儲按照自然順序對元素排序,但是對開發者不可見。
我們通過例子,演示下,Map集合的無序性:
~~~
fun main(args: Array<String>) {
//LinkedHashMap 插入順序
val map1 = mapOf<String, Int>(
Pair("J-1-佳佳", 168),
Pair("Q-2-巧巧", 165),
Pair("Y-3-依依", 170),
Pair("T-4-婷婷", 172),
Pair("B-5-貝貝", 163)
)
println("${map1}")
//HashMap無序
val map2 = hashMapOf<String, Int>(
Pair("J-1-佳佳", 168),
Pair("Q-2-巧巧", 165),
Pair("Y-3-依依", 170),
Pair("T-4-婷婷", 172),
Pair("B-5-貝貝", 163)
)
println("${map2}")
//LinkedHashMap 插入順序
val map3 = mutableMapOf<String, Int>(
Pair("J-1-佳佳", 168),
Pair("Q-2-巧巧", 165),
Pair("Y-3-依依", 170),
Pair("T-4-婷婷", 172),
Pair("B-5-貝貝", 163)
)
println("${map3}")
//TreeMap 自然順序
val map4 = TreeMap<String, Int>()
map4.put("J-1-佳佳", 168)
map4.put("Q-2-巧巧", 165)
map4.put("Y-3-依依", 170)
map4.put("T-4-婷婷", 172)
map4.put("B-5-貝貝", 163)
println("${map4}")
}
~~~
運行結果
```
{J-1-佳佳=168, Q-2-巧巧=165, Y-3-依依=170, T-4-婷婷=172, B-5-貝貝=163}
{Q-2-巧巧=165, Y-3-依依=170, J-1-佳佳=168, T-4-婷婷=172, B-5-貝貝=163}
{J-1-佳佳=168, Q-2-巧巧=165, Y-3-依依=170, T-4-婷婷=172, B-5-貝貝=163}
{B-5-貝貝=163, J-1-佳佳=168, Q-2-巧巧=165, T-4-婷婷=172, Y-3-依依=170}
Process finished with exit code 0
```
- 前言
- Kotlin簡介
- IntelliJ IDEA技巧總結
- idea設置類注釋和方法注釋模板
- 像Android Studion一樣創建工程
- Gradle
- Gradle入門
- Gradle進階
- 使用Gradle創建一個Kotlin工程
- 環境搭建
- Androidstudio平臺搭建
- Eclipse的Kotlin環境配置
- 使用IntelliJ IDEA
- Kotlin學習路線
- Kotlin官方中文版文檔教程
- 概述
- kotlin用于服務器端開發
- kotlin用于Android開發
- kotlin用于JavaScript開發
- kotlin用于原生開發
- Kotlin 用于數據科學
- 協程
- 多平臺
- 新特性
- 1.1的新特性
- 1.2的新特性
- 1.3的新特性
- 開始
- 基本語法
- 習慣用法
- 編碼規范
- 基礎
- 基本類型
- 包與導入
- 控制流
- 返回與跳轉
- 類與對象
- 類與繼承
- 屬性與字段
- 接口
- 可見性修飾符
- 擴展
- 數據類
- 密封類
- 泛型
- 嵌套類
- 枚舉類
- 對象
- 類型別名
- 內嵌類
- 委托
- 委托屬性
- 函數與Lambda表達式
- 函數
- Lambda表達式
- 內聯函數
- 集合
- 集合概述
- 構造集合
- 迭代器
- 區間與數列
- 序列
- 操作概述
- 轉換
- 過濾
- 加減操作符
- 分組
- 取集合的一部分
- 取單個元素
- 排序
- 聚合操作
- 集合寫操作
- List相關操作
- Set相關操作
- Map相關操作
- 多平臺程序設計
- 平臺相關聲明
- 以Gradle創建
- 更多語言結構
- 解構聲明
- 類型檢測與轉換
- This表達式
- 相等性
- 操作符重載
- 空安全
- 異常
- 注解
- 反射
- 作用域函數
- 類型安全的構造器
- Opt-in Requirements
- 核心庫
- 標準庫
- kotlin.test
- 參考
- 關鍵字與操作符
- 語法
- 編碼風格約定
- Java互操作
- Kotlin中調用Java
- Java中調用Kotlin
- JavaScript
- 動態類型
- kotlin中調用JavaScript
- JavaScript中調用kotlin
- JavaScript模塊
- JavaScript反射
- JavaScript DCE
- 原生
- 并發
- 不可變性
- kotlin庫
- 平臺庫
- 與C語言互操作
- 與Object-C及Swift互操作
- CocoaPods集成
- Gradle插件
- 調試
- FAQ
- 協程
- 協程指南
- 基礎
- 取消與超時
- 組合掛起函數
- 協程上下文與調度器
- 異步流
- 通道
- 異常處理與監督
- 共享的可變狀態與并發
- Select表達式(實驗性)
- 工具
- 編寫kotlin代碼文檔
- 使用Kapt
- 使用Gradle
- 使用Maven
- 使用Ant
- Kotlin與OSGI
- 編譯器插件
- 編碼規范
- 演進
- kotlin語言演進
- 不同組件的穩定性
- kotlin1.3的兼容性指南
- 常見問題
- FAQ
- 與Java比較
- 與Scala比較(官方已刪除)
- Google開發者官網簡介
- Kotlin and Android
- Get Started with Kotlin on Android
- Kotlin on Android FAQ
- Android KTX
- Resources to Learn Kotlin
- Kotlin樣品
- Kotlin零基礎到進階
- 第一階段興趣入門
- kotlin簡介和學習方法
- 數據類型和類型系統
- 入門
- 分類
- val和var
- 二進制基礎
- 基礎
- 基本語法
- 包
- 示例
- 編碼規范
- 代碼注釋
- 異常
- 根類型“Any”
- Any? 可空類型
- 可空性的實現原理
- kotlin.Unit類型
- kotlin.Nothing類型
- 基本數據類型
- 數值類型
- 布爾類型
- 字符型
- 位運算符
- 變量和常量
- 語法和運算符
- 關鍵字
- 硬關鍵字
- 軟關鍵字
- 修飾符關鍵字
- 特殊標識符
- 操作符和特殊符號
- 算術運算符
- 賦值運算符
- 比較運算符
- 邏輯運算符
- this關鍵字
- super關鍵字
- 操作符重載
- 一元操作符
- 二元操作符
- 字符串
- 字符串介紹和屬性
- 字符串常見方法操作
- 字符串模板
- 數組
- 數組介紹創建及遍歷
- 數組常見方法和屬性
- 數組變化以及下標越界問題
- 原生數組類型
- 區間
- 正向區間
- 逆向區間
- 步長
- 類型檢測與類型轉換
- is、!is、as、as-運算符
- 空安全
- 可空類型變量
- 安全調用符
- 非空斷言
- Elvis操作符
- 可空性深入
- 可空性和Java
- 函數
- 函數式編程概述
- OOP和FOP
- 函數式編程基本特性
- 組合與范疇
- 在Kotlin中使用函數式編程
- 函數入門
- 函數作用域
- 函數加強
- 命名參數
- 默認參數
- 可變參數
- 表達式函數體
- 頂層、嵌套、中綴函數
- 尾遞歸函數優化
- 函數重載
- 控制流
- if表達式
- when表達式
- for循環
- while循環
- 循環中的 Break 與 continue
- return返回
- 標簽處返回
- 集合
- list集合
- list集合介紹和操作
- list常見方法和屬性
- list集合變化和下標越界
- set集合
- set集合介紹和常見操作
- set集合常見方法和屬性
- set集合變換和下標越界
- map集合
- map集合介紹和常見操作
- map集合常見方法和屬性
- map集合變換
- 集合的函數式API
- map函數
- filter函數
- “ all ”“ any ”“ count ”和“ find ”:對集合應用判斷式
- 別樣的求和方式:sumBy、sum、fold、reduce
- 根據人的性別進行分組:groupBy
- 扁平化——處理嵌套集合:flatMap、flatten
- 惰性集合操作:序列
- 區間、數組、集合之間轉換
- 面向對象
- 面向對象-封裝
- 類的創建及屬性方法訪問
- 類屬性和字段
- 構造器
- 嵌套類(內部類)
- 枚舉類
- 枚舉類遍歷&枚舉常量常用屬性
- 數據類
- 密封類
- 印章類(密封類)
- 面向對象-繼承
- 類的繼承
- 面向對象-多態
- 抽象類
- 接口
- 接口和抽象類的區別
- 面向對象-深入
- 擴展
- 擴展:為別的類添加方法、屬性
- Android中的擴展應用
- 優化Snackbar
- 用擴展函數封裝Utils
- 解決煩人的findViewById
- 擴展不是萬能的
- 調度方式對擴展函數的影響
- 被濫用的擴展函數
- 委托
- 委托類
- 委托屬性
- Kotlin5大內置委托
- Kotlin-Object關鍵字
- 單例模式
- 匿名類對象
- 伴生對象
- 作用域函數
- let函數
- run函數
- with函數
- apply函數
- also函數
- 標準庫函數
- takeIf 與 takeUnless
- 第二階段重點深入
- Lambda編程
- Lambda成員引用高階函數
- 高階函數
- 內聯函數
- 泛型
- 泛型的分類
- 泛型約束
- 子類和子類型
- 協變與逆變
- 泛型擦除與實化類型
- 泛型類型參數
- 泛型的背后:類型擦除
- Java為什么無法聲明一個泛型數組
- 向后兼容的罪
- 類型擦除的矛盾
- 使用內聯函數獲取泛型
- 打破泛型不變
- 一個支持協變的List
- 一個支持逆變的Comparator
- 協變和逆變
- 第三階段難點突破
- 注解和反射
- 聲明并應用注解
- DSL
- 協程
- 協程簡介
- 協程的基本操作
- 協程取消
- 管道
- 慕課霍丙乾協程筆記
- Kotlin與Java互操作
- 在Kotlin中調用Java
- 在Java中調用Kotlin
- Kotlin與Java中的操作對比
- 第四階段專題練習
- 朱凱Kotlin知識點總結
- Kotlin 基礎
- Kotlin 的變量、函數和類型
- Kotlin 里那些「不是那么寫的」
- Kotlin 里那些「更方便的」
- Kotlin 進階
- Kotlin 的泛型
- Kotlin 的高階函數、匿名函數和 Lambda 表達式
- Kotlin協程
- 初識
- 進階
- 深入
- Kotlin 擴展
- 會寫「18.dp」只是個入門——Kotlin 的擴展函數和擴展屬性(Extension Functions / Properties)
- Kotlin實戰-開發Android