• Map集合(超详解)


    特点:

    1.无序,键值对,键不能重复,值可以重复,这里的无序指的也是插入的顺序和读取的顺序是不一样的,和set集合一样。

    2. 键重复则覆盖,没有继承Collection接口,它单独继承Map接口,和list,set不一样,这两个继承collection接口

    扩容:

    初始容量16,负载因子0.75,扩容增量1倍



    遍历:

    先获取所有键的Set集合,再遍历(通过键获取值)取出保存所有Entry的Set,再遍历此Set即可。

    map的实现类

    HashMap

    1. 线程不安全,最常用,速度快

    2. 内部采用数组来存放数据

    put的执行过程

     流程图中绿色标出的部分为JDK8新增的处理逻辑,目的是在Table[i]中的Node节点数量大于8时,通过红黑树提升查找速度。

    Table数组中的的Node

    jdk1.8之前的链表结构示意图

    jdk1.8 后的红黑树示意图

     在这里,不得不说一下,什么是红黑树

    特性:

    1. 每个节点要么红要么黑
    2. 根节点是黑色
    3 .每个叶子节点都是黑色(叶子是NULL节点表示 或 NIL节点表示)。
    4. 如果一个节点是红色的,那么它的子节点必须是黑色的子节点。(即不存在两个连续的红色节点)
    5. 从任一节点到其每个叶子结点(NULL节点或 NIL节点)的所有简单路径都包含相同数目的黑色节点。
     

    红黑树其实就是以第一个数据作为判断依据,后面进来的数据与其做比较,比他小的就在这个数的左边,比这个数大的就在右边,然后继续往下走,接在下面一步一步往下走,这就是红黑树。

     这里提供一个可视化红黑树网址

    点我跳转红黑树https://www.cs.usfca.edu/~galles/visualization/RedBlack.html说完红黑树,我们来说一下jdk1.8之前的hashmap的原理怎么样的

    首先在hashmap的底层有一个叫桶的数组,默认长度为16,这数组并不是保存的我们进来的元素,而是保存一个指向数据节点的一个指针,引用,首先通过key值hash运算,得到hashcould值,然后确定在数组上的位置,然后数据进来一个一个往下面的链表挤,往下挤,无论你有多少的元素我都一直往下挤。

    而在jdk1.8后,先进行一个判断,判断你的元素长度是否大于8,如果小于8是一个链表结构,如果大于8是一个红黑树的结构,红黑树结构上面已经说了,所以这就是jdk1.8之后的一个区别,这样的结构使得map的速度更快了。

    HashTable

    线程安全,不太常用,与vector类似,将所有数据加一把锁,性能很高

    ConcurrentHashMap

    线程安全,比HashTable性能高,jdk1.8之前采用16把分段锁,将数据加锁,jdk1.8之后是每一个在数组的桶加锁,每一个桶一把锁,有多少桶就加多少锁,中间在赋值的时候才用的是cas,比较并替换。

    TreeMap

    key值按一定的顺序排序,添加或获取元素时性能较HashMap慢,因为需求维护内部的红黑树,用于保证key值的顺序

    LinkedHashMap

    继承HashMap

    LinkedHashMap是有序的,且默认为插入顺序

    当我们希望有顺序地去存储key-value时,就需要使用LinkedHashMap了

    代码实现

    1. Map<String, String> linkedHashMap = new LinkedHashMap<>();
    2. linkedHashMap.put("name1", "josan1");
    3. linkedHashMap.put("name2", "josan2");
    4. linkedHashMap.put("name3", "josan3");
    5. Set<Entry<String, String>> set = linkedHashMap.entrySet();
    6. Iterator<Entry<String, String>> iterator = set.iterator();
    7. while(iterator.hasNext()) {
    8. Entry entry = iterator.next();
    9. String key = (String) entry.getKey();
    10. String value = (String) entry.getValue();
    11. System.out.println("key:" + key + ",value:" + value);
    12. }

    案例代码,上面的具体代码

    1. package com.zking.test;
    2. import java.util.HashMap;
    3. import java.util.Hashtable;
    4. import java.util.Iterator;
    5. import java.util.Map;
    6. import java.util.Map.Entry;
    7. import java.util.concurrent.ConcurrentHashMap;
    8. import org.junit.Before;
    9. import org.junit.Test;
    10. public class Maptest {
    11. private Map<String, String> map = new HashMap<>();
    12. @Before
    13. public void setup() {
    14. map.put("1", "李凝");
    15. map.put("2", "张山");
    16. map.put("3", "吴飞");
    17. map.put("4", "徐民");
    18. }
    19. @Test
    20. public void demo1() {
    21. System.out.println(map.get("3"));
    22. }
    23. @Test
    24. public void demo() {
    25. map.put("5", "zs");
    26. System.out.println(map.get("1"));
    27. System.out.println(map.get("5"));
    28. }
    29. @Test
    30. public void demo2() {
    31. Iterator<String> it = map.keySet().iterator();
    32. while (it.hasNext()) {
    33. String key = it.next();
    34. System.out.println(map.get(key));
    35. }
    36. // 获取value值
    37. }
    38. @Test
    39. public void demo9() {
    40. Iterator<Entry<String, String>> it = map.entrySet().iterator();
    41. while (it.hasNext()) {
    42. Entry<String, String> entry = it.next();
    43. System.out.println(entry.getKey() + ": " + entry.getValue());
    44. }
    45. // 获取key+value值
    46. }
    47. @Test
    48. public void demo10() {
    49. map.forEach((key, val) -> System.out.println(key + ":" + val));
    50. // foreach遍历出key+value值
    51. }
    52. @Test
    53. public void demo11() {
    54. if (!map.containsKey("4")) {
    55. map.put("4", "徐民");
    56. }
    57. map.putIfAbsent("4", "白牙");
    58. // map.putIfAbsent()如果这元素存在就不覆盖,put如果存在就覆盖
    59. // 使用 put 方法添加键值对,如果 map 集合中没有该 key 对应的值,则直接添加,
    60. // 并返回 value;如果已经存在对应的值,则会覆盖旧值,value 为新的值,返回值为 value。
    61. //
    62. // 2.使用 putIfAbsent 方法添加键值对,如果 map 集合中没有该 key 对应的值,则直接添加,
    63. // 并返回 null,如果已经存在对应的值,则依旧为原来的值,返回值为 value(旧的值)。
    64. map.forEach((key, val) -> System.out.println(key + ":" + val));
    65. }
    66. @Test
    67. public void demo3() {
    68. Map<String, String> map = new HashMap<>();
    69. map.put("1", "李凝");
    70. map.put("2", "张山");
    71. map.put("3", "吴飞");
    72. map.put("4", "徐民");
    73. Iterator<Entry<String, String>> it = map.entrySet().iterator();
    74. while (it.hasNext()) {
    75. Entry<String, String> next = it.next();
    76. System.out.println(next.getKey() + " : " + next.getValue());
    77. }
    78. // 迭代器遍历出元素
    79. }
    80. @Test
    81. public void demo4() {
    82. // 对已存在的key为1的记录进行了覆盖
    83. map.put("1", "微信");
    84. System.out.println(map.get("1"));
    85. }
    86. @Test
    87. public void demo5() {
    88. // 如果指定的key值不存在,则加入map
    89. if (!map.containsKey("2")) {
    90. map.put("2", "rest");
    91. }
    92. // 更简单的方式
    93. String val = map.putIfAbsent("2", "rest");
    94. System.out.println(map.get("2"));
    95. System.out.println(val);
    96. }
    97. @Test
    98. public void demo6() {
    99. map.remove("1");
    100. map.forEach((key, val) -> System.out.println(key + ":" + val));
    101. //删除方法
    102. }
    103. @Test
    104. public void demo12() {
    105. Hashtable<String, String> table = new Hashtable();
    106. table.put("1", "指针");
    107. table.forEach((key, val) -> System.out.println(key + ": " + val));
    108. // Hashtable
    109. }
    110. @Test
    111. public void demo13() {
    112. ConcurrentHashMap<String, String> table = new ConcurrentHashMap<>();
    113. table.put("1", "指针");
    114. table.forEach((key, val) -> System.out.println(key + ": " + val));
    115. }
    116. // ConcurrentHashMap
    117. }
    1. private TreeMap<String,Student> treeMap;
    2. @Before
    3. public void setup() {
    4. treeMap = new TreeMap<String,Student>(new Comparator<String>() {
    5. @Override
    6. public int compare(String o1, String o2) {
    7. // TODO Auto-generated method stub
    8. // 负数 0 正数
    9. return o1.compareTo(o2);
    10. }
    11. });
    12. treeMap.put("1", new Student(1, "zs", 0));
    13. treeMap.put("2", new Student(3, "ls", 0));
    14. treeMap.put("3", new Student(2, "ww", 0));
    15. treeMap.put("4", new Student(4, "zl", 0));
    16. }
    17. @Test
    18. public void demo1() {
    19. treeMap.forEach((key, val) -> System.out.println(key + ":" + val));
    20. }

  • 相关阅读:
    每日一题:爬楼梯
    使用Tmux的基本操作与后台运行命令
    MySQL 安装+启动+报错的解决方案
    面试官: 有了解过CAS和原子操作吗?说说看
    新人必看!手把手教你如何使用浏览器表格插件(上)
    刷题笔记(牛客java选择题)
    【Python面向对象进阶①】——给对象动态的增加属性和方法
    如何在 Unbuntu 下安装配置 Apache Zookeeper
    Python版A股选股软件源代码,选股系统源代码,实现多种选股策略
    java计算机毕业设计校园代购服务订单管理系统源码+系统+mysql数据库+lw文档+部署
  • 原文地址:https://blog.csdn.net/weixin_67150631/article/details/125511020