精讲-第5章(15)map集合-上
map集合介绍
相比于List、Set。Map 则提供了元素存储的另外一种方式。Map 集合类用于存储键值对(key-value),一个键(key)对应一个值(value),键(key)不能重复。
举个例子,比如教室里面所有学生的姓名,我们用list集合存储不用考虑太多,用set集合存储就需要考虑班级同学名字是否有重复的,因为set会去重。
如果用map集合存储,则需要考虑的更多,首先要考虑把名字做为key还是作为value。如果把名字作为key,那要考虑,班上同学名字是否有重复,有重复的就不能作为key,map集合key不能重复的。假如名字不重复,名字可以作为key,那继续考虑,每个key对应的value是什么,比如可以是学生成绩、身高等,map集合value可以重复。这样,一个学生姓名可以找到一个学生成绩、身高等数据。
如果把名字定为value,班上同学名字是否有重复则不重要,那你就要为每一个名字找一个唯一不重复的key,比如可以是学号,学号都是唯一的。这样一个学号就可以找到一个学生。
从代码角度去理解, map集合由Map接口和Map接口的实现类组成。
Map接口常用的实现类有哪些? HashMap、LinkedHashMap、TreeMap和MutableHashMap。
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种方式的对应方法的方法签名,重点看返回值,方法体的部分我直接去掉了,对应的源码如下:
作为了解,可以通过翻看源码得知4种创建集合方式上的细微差别,有的是通过Java里面的HashMap创建,有的是通过LinkedHashMap。这个意义不是很大。
更需要知道的是,返回Map不可写,返回HashMap、MutableMap、TreeMap可写。具体使用的时候,忘记是否可写怎么办?只需要点进去看看方法的返回值即可。或者,看每个方法的注释,返回只读的map集合,会出现“read-only list”字样。比如查看mapof方法的定义,参考截图:
我们通过代码演示集合的四种创建方式:
针对上面的代码。第一,4种方式创建的时候,都指定了map集合中元素的类型。第二,mapOf()、hashMapOf ()、mutableMapOf ()中包含的Pair类型的元素,都是通过Pair的构造方法创建的。
如果是通过mapOf()、hashMapOf ()、mutableMapOf ()三个方法创建map集合,而且调用方法的时候,有往map集合中传入至少一个元素,那么编译器是可以帮助我们完成map集合中元素类型的自动推断的,参考代码:
mapOf()、hashMapOf ()、mutableMapOf ()中包含的Pair类型的元素,**除了通过Pair的构造方法创建,还可以通过to方法。**我们看to方法的定义如下:
可以看到是一个带infix关键字的中缀函数。所以,我们创建map的时候,还可以有如下的常用形式,参考代码:
【代码清单-Map_创建_3_to方法.kt】
map集合可写性验证以及转换
我们通过代码验证集合是否可写,先验证集合可写,参考代码:
我们在验证集合不可写,参考代码:
但是,不可写集合可以通过totoMutableMap转换为可写集合,然后在进行写操作,参考代码:
map集合数据可重复
map集合中的元素可重复,是list相对于set的一个重要特点。同时,map集合中可以存储null元素,我们通过一个案例验证下map集合可以包含重复代码,参考代码:
map集合遍历操作
前面我们学习了区间的遍历,数组的遍历。那如何遍历map集合呢?map集合的遍历和数组的遍历一样。
也就是map集合在遍历的时候,可以普通的for循环,还可以for循环的时候调用withIndex方法,参考代码:
当然,还可以通过高阶函数进行遍历操作,这个我们后续再去讲解。
map集合数据无序
同set集合,map集合同样无序,应该怎么去理解呢?就是我们的Map接口,不保证加入和取出顺序一致。但是子接口会做一些保证。
HashMap内部存储的时候会根据元素的hashCode排序,元素取出的时候无序。
LinkedHashMap内部存储的时候也会根据元素的hashCode排序,但是使用链表存储,元素取出顺序和插入顺序一致。
TreeSet内部存储按照自然顺序对元素排序,但是对开发者不可见。
我们通过例子,演示下,Map集合的无序性: