目录
无序,键值对,键不能重复,值可以重复,键重复则覆盖,没有继承Collection接口
扩容:初始容量16,负载因子0.75,扩容增量1倍
准备数据
- private Map<String, Object>map=new HashMap<String, Object>();
-
- @Before
- public void setup() {
- map.put("1", "鼠标");
- map.put("1", "电脑");
- map.put("2", "风扇");
- map.put("3", "书包");
- map.put("4", "演讲");
- map.putIfAbsent("1", "aaa");//如果缺失则加进去
- }
-
🟡先获取所有键的Set集合,再遍历(通过键获取值)
- @Test
- public void test01() {
- Iterator<String>it=map.keySet().iterator();
- while(it.hasNext()) {
- String key = it.next();
- System.out.println(map.get(key));
- }
- }
效果图如下:
🟡取出保存所有Entry的Set,再遍历此Set即可
- @Test
- public void test02() {
- Iterator<Entry<String, Object>> it = map.entrySet().iterator();
- while(it.hasNext()) {
- Entry e=it.next();
- System.out.println("key = "+ e.getKey() +" value ="+ e.getValue());
- }
- }
效果图如下:
HashMap的线程不安全,但是最为常用,速度快。内部采用数组来存放数据。
首先来了解了解执行过程
当我们往map里面put 元素时,会先检查这个数组是否存在。若没有存在,则会分配一个默认长度为16的数组。数组里面不是直接保存元素,而是经过一系列运算,通过给出的key获取到key在数组中的位置,这个数组称为桶(通过计算算出节点在几号桶里面)。图中桶指向的元素是Node节点(Node实际是Entry<k,v>)。每次添加元素时会经过计算,若没有元素,则会声明一个节点放进去,如果存放的元素是一样的则会被覆盖,反之,则会通过链表的方式往下增加(新增得元素在上方,原来的元素往下走)。
如何拿值?先经过计算,通过key找到元素所在的桶,若发现是一个链表,则进行链表遍历的方式找到元素。
在元素多的情况下,上面的方法查找的时候需要全部遍历,存在缺点。运用二叉树的方式进行查找 ,通过元素的条件进行遍历,不需要那个链表都进行遍历。
了解结构之后再来看看基本原理
首先向Map里面put值,若发现为空,生成一个新的空,再根据key的hush值计算数组中对应的下标。如果数组里面没有值则生成一个新的节点,有值得话就生成节点进行判断,若大于8,转换为红黑树保存节点信息,不大于8就将信息保存到链表中。
注意:流程图中绿色标出的部分为JDK8新增的处理逻辑,目的是在Table[i]中的Node节点数量大于8时,通过红黑树提升查找速度。
HashTable线程安全但是不为常用
- public void test03() {
- Map<Integer, Object>table=new Hashtable<Integer, Object>();
- table.put(1, "张三");
- table.put(2, "李四");
- table.put(3, "王五");
- table.put(4, "老刘");
- Iterator<Integer> it = table.keySet().iterator();
- while(it.hasNext()) {
- int key=it.next();
- System.out.println(table.get(key));
- }
- }
线程安全,比HashTable性能高
- public void test04() {
- Map<Integer, Object>cmap=new ConcurrentHashMap<Integer, Object>();
- cmap.put(1, "张三");
- cmap.put(2, "李四");
- cmap.put(3, "王五");
- cmap.put(4, "老刘");
- Iterator<Integer> it = cmap.keySet().iterator();
- while(it.hasNext()) {
- int key=it.next();
- System.out.println(cmap.get(key));
- }
- }
key值按一定的顺序排序,添加或获取元素时性能较HashMap慢,是因为需求维护内部的红黑树,用于保证key值的顺序。
- public void test05() {
- Map<Integer, Object>tmap=new TreeMap<Integer, Object>();
- tmap.put(1, "张三");
- tmap.put(2, "李四");
- tmap.put(3, "王五");
- tmap.put(4, "老刘");
- Iterator<Integer> it = tmap.keySet().iterator();
- while(it.hasNext()) {
- int key=it.next();
- System.out.println(tmap.get(key));
- }
- }
key值默认为升序,若想按照降序排序可以使用比较器(用key进行比较)
- public void test05() {
- Map<Integer, Object>tmap=new TreeMap<Integer, Object>(new Comparator<Integer>() {
-
- @Override
- public int compare(Integer o1, Integer o2) {
-
- return o2-o1;
- }
- });
- tmap.put(1, "张三");
- tmap.put(2, "李四");
- tmap.put(3, "王五");
- tmap.put(4, "老刘");
- Iterator<Integer> it = tmap.keySet().iterator();
- while(it.hasNext()) {
- int key=it.next();
- System.out.println(tmap.get(key));
- }
- }
效果图如下:
继承HashMap,LinkedHashMap是有序的,且默认为插入顺序,当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了
- public void test06() {
- Map<String, String> linkedHashMap = new LinkedHashMap<>();
- linkedHashMap.put("name1", "josan1");
- linkedHashMap.put("name2", "josan2");
- linkedHashMap.put("name3", "josan3");
- Set<Entry<String, String>> set = linkedHashMap.entrySet();
- Iterator<Entry<String, String>> iterator = set.iterator();
- while(iterator.hasNext()) {
- Entry entry = iterator.next();
- String key = (String) entry.getKey();
- String value = (String) entry.getValue();
- System.out.println("key:" + key + ",value:" + value);
- }
- }
效果如下: