• List,Set,Map集合总结


    导语

    集合其实就是一个可以自动扩容的数组,它有一个默认长度,List的默认长度是10,增长因子是0.5;Set,Map默认长度为16,增长因子为0.75。但他们的具体原理又不一样,实现类也不一样,接下来,让我们一起去回顾一下吧!

    List

    首先它的实现类有:arraylist,LinkedList,Vector,CopyOnWriteArrayList。

    arraylist是list最常用的实现类,但它其实是线程不安全的,但是是放在类变量的时候是不安全的,如果作为成员变量,方法变量其实安全的,因为这不存在线程安全不安全的问题。array list的内部就是封装好的数组, 所以它额随机访问速度在list中是最快的,但如果是集合的使用的话,如果它的数据访问量较小,那么list的随机访问速度要快,如果是数据的访问量大的话,HashMap 的访问速度肯要比array list要快。

    在这里我们在回顾一下我们的list删除的时候要注意的点

    1. package com.zking.test;
    2. import java.util.ArrayList;
    3. import java.util.Iterator;
    4. import java.util.List;
    5. import org.junit.Before;
    6. import org.junit.Test;
    7. public class Tesylist {
    8. List<Integer> list;
    9. @Before
    10. public void setup() {
    11. list = new ArrayList<Integer>();
    12. list.add(1);
    13. list.add(4);
    14. list.add(8);
    15. list.add(8);
    16. list.add(12);
    17. list.add(16);
    18. }
    19. /**
    20. * 删除元素为8的元素
    21. */
    22. @Test
    23. public void listDel01() {
    24. for (int i = 0; i < list.size(); i++) {
    25. if (list.get(i) == 8)
    26. list.remove(i);
    27. }
    28. System.out.println(list);
    29. // 结果:[1,4,8,12,16],这种方式直接找到第一个元素8,找到后直接删除结束
    30. }
    31. @Test
    32. public void listDel02() {
    33. for (int i = 0; i < list.size(); i++) {
    34. if (list.get(i) == 8)
    35. list.remove(i--);
    36. }
    37. System.out.println(list);
    38. // 结果:[1,4,12,16] 这种方式找到第一个8 删除,但第二个8同时发生移位,
    39. // 直接跳到第一个8 的位置,但此时指针还未移动,所以又删除一个8 后才往下据继续移动
    40. }
    41. @Test
    42. public void listDel03() {
    43. for (int i = list.size() - 1; i >= 0; i--) {
    44. if (list.get(i) == 8) {
    45. list.remove(i);
    46. }
    47. }
    48. System.out.println(list);
    49. // 结果:[1,4,12,16] 这种方式是将集合到过来进行遍历删除,第二个8发生移位但又移动
    50. // 到了指针还为移动位置,然后删除了
    51. }
    52. @Test
    53. public void listDel04() {
    54. for (Integer i : list) {
    55. if (i == 8)
    56. list.remove(i);
    57. }
    58. System.out.println(list);
    59. // 结果:执行错误
    60. }
    61. @Test
    62. public void listDel05() {
    63. Iterator<Integer> it = list.iterator();
    64. while (it.hasNext()) {
    65. if (it.next() == 8) {
    66. it.remove();
    67. }
    68. }
    69. System.out.println(list);
    70. // 结果:[1,4,12,16]迭代器
    71. }
    72. @Test
    73. public void listDel06() {
    74. Iterator<Integer> it = list.iterator();
    75. while (it.hasNext()) {
    76. Integer value = it.next();
    77. if (value == 8) {
    78. list.remove(value);
    79. }
    80. }
    81. System.out.println(list);
    82. // 结果:执行不通过
    83. }
    84. @Test
    85. public void listDel07() {
    86. // ist.add(1);
    87. // list.add(4);
    88. // list.add(8);
    89. // list.add(8);
    90. // list.add(12);
    91. // list.add(16);
    92. list.add(4);
    93. // 结果: [1,4,8,12,16],在这里,删除的是下标为4的元素,刚好为元素8
    94. list.remove(Integer.valueOf(4));
    95. System.out.println(list);
    96. // 结果: [1,8,8,12,16],在这里,删除的是元素为4的元素,以为通过
    97. // integer.valueof()将4转成了一个对象4,所以删除的是4而不是下标为4的元素
    98. }
    99. }

    说完这个array list,我们在来说一下这个其他的实现类

    LinkedList

    1. linkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部

    2. 线程不安全

    3. LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)

    4. 以双向链表实现,链表无容量限制,允许元素为null,线程不安全

    5. 适合做随机的增加或删除

    Vector

    1. 线程安全

    2. 并行性能慢,不建议使用

    CopyOnWriteArrayList

    这个实现类有点意思,因为它是采用的是写实复制的一种最终一致性的实现类,它线程安全,性能比vector的高。

    1.写时复制

    2. 线程安全

    3. 适合于读多,写少的场景

    4. 写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array

    5. 比Vector性能高

    6.最终一致性

    7.实现了List接口,使用方式与ArrayList类似

    缺点:要等数据修改完了之后才能读取到,在修改数据时别人无法读取新数据,但值得一提的是在在复制和替换的时候这个时间是非常短的,所以我们也可以放心大胆使用。

    这里提供一个详细的李斯特讲解的博客

    李斯特详解icon-default.png?t=M5H6https://blog.csdn.net/weixin_67150631/article/details/125475936

    Set

    和list不一样

    1. 特点:无序,不重复

    2. 遍历:foreach,迭代器

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

    李斯特可以重复元素,然后又顺序,但按list的内容进行删除的时候如果不注意可能会出现问题,在这里我也提供一个链接,介绍了set和List为什么删除会出错的原因

    Set详解icon-default.png?t=M5H6https://blog.csdn.net/weixin_67150631/article/details/125491767

    Set的实现类

    HashSet

    1.它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在

    2. 由HashMap支持

    3. 不保持插入顺序

    4. 非线程安全

    5. 性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);

    TreeSet

    1. 是一个包含有序的且没有重复元素的集合

    2. 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序

    3. TreeSet是基于TreeMap实现的

    Set中的比较器

    1.默认自然排序

    2.自定义排序

    --1. 较器通过构造函数传入比

    --2.  实现排序接口

    这俩种排序方法在上面的连接中有详细介绍,我就不多介绍了

    小结:Set和list都是继承的 Collection接口,而下面讲的Map却是继承单独的Map接口。

    Map

    特点:

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

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

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

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

    实现类:

    HashMap,HashTable,ConcurrentHashMap,TreeMap,LinkedHashMap

    最有意思的是这HashMap,因为它的底层原理可以说是链表结构加红黑树的结构,当你的数据没有超过8的时候,在hashmap桶中就会是一个链结构,当你数据超过8了,你的数据结构就会变成一个红黑数的结构来存储,这样的结构在我们读取数据的时候会更快。

    HashMap

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

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

    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. }

    想了解更为详细的Map知识的直接去这里:

    Map详解icon-default.png?t=M5H6https://blog.csdn.net/weixin_67150631/article/details/125511020

    总结:

    集合的使用在我们编码的过程中可以说是非常的常见,而集合的基本原理也先要我们去好好的了解,不然出Bug了怎么解决,有办法,来看我的博客!!!

    欢迎一键三连

  • 相关阅读:
    算法自学__线性筛
    电脑入门:路由器测试技术介绍及类型和方法
    B. 01 Game【模拟】
    百题千解计划【CSDN每日一练】计数问题(附解析+多种实现方法:Python、Java、C、C++、JavaScript、C#、go)
    无线网络存在的安全问题及现代化解决方案
    面试官:同学,冒泡太简单了,要不手写一个【快速排序】吧...
    Spring集合注入
    深究防火墙
    JADE盲分离算法仿真
    基于哈夫曼树的数据压缩算法
  • 原文地址:https://blog.csdn.net/weixin_67150631/article/details/125568863