• List集合详细讲解


      list集合想必大家都是不陌生的,我们用的也是非常的多,但是可能大家在使用中,也不是对list集合有非常详细的讲解,今天小编就详细的带大家了解list集合。

    目录

     一.集合之间的关系

     二.List集合

    三.ArrayList集合 

    for循环删除方法01

     for循环删除方法02

    for循环删除方法03

    foreach删除方法

    迭代器删除01

    迭代器删除元素02

    list集合删除方法

      四.LinkedList集合

    五.Vector集合 

    六.CopyOnWriteArrayList集合 


     一.集合之间的关系

    下方是一张UML图,vector,ArrayList,LinkedList继承List,今天也是详细讲解该三个集合,下一篇文章在给大家详细Set集合。

      


     二.List集合

      List集合特点:

           元素有序的,且可重复。(元素有序不是指,我们存进Lits集合中的什么1,3,7,6他给我们从小到大,或者从大到小这样子,所谓的有序是我们该集合有下标,下标从0开始,然后我们按照什么顺序增加到list集合的,那么他就是什么样子的顺序)。 

      

     List集合遍历:

          根据下标,foreach,迭代器遍历数据。

     

     Lits集合扩容:

          Lits集合当我们实例出来,它的默认初始容量为10,当往List集合里面增加的数据超过10个以后,他就会扩容增加0.5倍,扩容以后就是15。

          新容量 = 原容量 + 原容量 * 0.5

     

      注:vector,ArrayList,LinkedList都是继承List,所以和Lits集合以上三点都是一样的。


    三.ArrayList集合 

     ArrayList集合是继承List的集合的,所以Lits集合具备的一些特点,ArrayList也是具备的。

     ArrayList集合的特点:

    • 简单数据结构,超出容量会自动扩容,也是和List集合的扩容是一样的。
    • ArrayList集合动态数组,为什么说是动态数组,因为数组一般能存放多少数据,一般都是定好的,而ArrayList数组是可以根据数据扩容的,所以是一个动态的数组。
    • 内部实现是基于基础的对象数组的,也就是ArrayList集合存放的是对象。
    • ArrayList集合不适合随机的删除和增加。

       

      ArrayList删除几种删除

    • for循环删除方法01

           这种方法存在一个非常致命的问题,我这里的判断是删除为3的数据,集合中有两个为3的,但是只删除了一个3,得到的结果为[1, 2, 3, 4, 5, 6]

          为什么没有将2个3全部删除?

          因为在进行删除的时候会,本来集合数据为[1,2,3,3,4,5,6],但是在我们删除3的时候,集合立马就会变成[1,2,3,4,5,6]第二个3的下标网上移动了,而for循环已经走到下标为3的,而第一个3被在删除的那一刻第二个3的下标本来是3,但是立马下标为2了,所以这就是为什么结果为[1, 2, 3, 4, 5, 6],所以这种方法非常大的bug存在,因为想删除的数据没有删除成功。
     

    1. package patterndemo02;
    2. import java.util.ArrayList;
    3. import java.util.List;
    4. import org.junit.Before;
    5. import org.junit.Test;
    6. public class Test01 {
    7. private List<Integer> list=new ArrayList<Integer>();
    8. /**
    9. * 第一种删除方法
    10. */
    11. @Before
    12. public void list() {
    13. //往集合中增加数据
    14. list.add(1);
    15. list.add(2);
    16. list.add(3);
    17. list.add(3);
    18. list.add(4);
    19. list.add(5);
    20. list.add(6);
    21. }
    22. @Test
    23. public void test01() {
    24. for(int i=0;i<list.size();i++) {
    25. //判断当找到该对象值为3的删除
    26. if(list.get(i)==3) {
    27. list.remove(i);
    28. }
    29. }
    30. System.out.println(list);
    31. }
    32. }

       得到结果 

       

      

    •  for循环删除方法02

           这种方法将3全部删除了,因为首先判断为3的进行删除,但是i--的特点在于,第一遍不会立马执行i=i-1,等第二次的执行才会执行i=i-1,所以第一遍正常删除第一个三,第二遍删除第二个3所以结果为[1,2,4,5,6]

           

    1. package patterndemo02;
    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 Test01 {
    8. private List<Integer> list=new ArrayList<Integer>();
    9. /**
    10. * 第一种删除方法
    11. */
    12. @Before
    13. public void list() {
    14. //往集合中增加数据
    15. list.add(1);
    16. list.add(2);
    17. list.add(3);
    18. list.add(3);
    19. list.add(4);
    20. list.add(5);
    21. list.add(6);
    22. }
    23. @Test
    24. public void test02() {
    25. for(int i=0;i<list.size();i++) {
    26. if(list.get(i)==3) {
    27. list.remove(i--);
    28. }
    29. }
    30. System.out.println(list);
    31. }
    32. }

     得到结果:

        

      

    • for循环删除方法03

        大家看这个图更好理解,图片画的有点丑。

       

     

    1. package patterndemo02;
    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 Test01 {
    8. private List<Integer> list=new ArrayList<Integer>();
    9. /**
    10. * 第一种删除方法
    11. */
    12. @Before
    13. public void list() {
    14. //往集合中增加数据
    15. list.add(1);
    16. list.add(2);
    17. list.add(3);
    18. list.add(3);
    19. list.add(4);
    20. list.add(5);
    21. list.add(6);
    22. }
    23. @Test
    24. public void test03() {
    25. for(int i=list.size()-1;i>=0;i--){
    26. if(list.get(i)==3){
    27. list.remove(i);
    28. }
    29. }
    30. }
    31. }

     得出结果

     

     

        

    • foreach删除方法

      

         这种方法就是非常严重的问题,因为报错,所以不要使用foreach删除。

        

    1. public void test04() {
    2. for(Integer i:list){
    3. if(i==3) list.remove(i);
    4. }
    5. System.out.println(list);
    6. }

        这种方法有一个非常有意思的地方,就是他可以删除倒数第二个元素,不会报错,会删除成功,这也算是一个小bug。

       

    1. @Test
    2. public void test04() {
    3. for(Integer i:list){
    4. if(i==3) {
    5. list.remove(5);
    6. }
    7. }
    8. System.out.println(list);
    9. }

      

       为什么使用foreach删除报错???
        首先foreach在本质上创建了迭代器,我们先看下源码。

         

    1. private class Itr implements Iterator<E> {
    2. int cursor; // index of next element to return
    3. int lastRet = -1; // index of last element returned; -1 if no such
    4. int expectedModCount = modCount;
    5. Itr() {}
    6. //1.
    7. public boolean hasNext() {
    8. return cursor != size;
    9. }
    10. //2.
    11. public E next() {
    12. checkForComodification();
    13. int i = cursor;
    14. if (i >= size)
    15. throw new NoSuchElementException();
    16. Object[] elementData = ArrayList.this.elementData;
    17. if (i >= elementData.length)
    18. throw new ConcurrentModificationException();
    19. cursor = i + 1;
    20. return (E) elementData[lastRet = i];
    21. }
    22. //3.
    23. public void remove() {
    24. if (lastRet < 0)
    25. throw new IllegalStateException();
    26. checkForComodification();
    27. try {
    28. ArrayList.this.remove(lastRet);
    29. cursor = lastRet;
    30. lastRet = -1;
    31. expectedModCount = modCount;
    32. } catch (IndexOutOfBoundsException ex) {
    33. throw new ConcurrentModificationException();
    34. }
    35. }
    36. //4.
    37. final void checkForComodification() {
    38. if (modCount != expectedModCount)
    39. throw new ConcurrentModificationException();
    40. }
    41. }

         注意看这个方法 

            

    1. //4.
    2. final void checkForComodification() {
    3. if (modCount != expectedModCount)
    4. throw new ConcurrentModificationException();
    5. }

     modCount:修改次数 

    当list调动add方法时,add方法会对 modCount 实现++操作,如上例,共调用了add()4次,
    则modCount=4。
    而在迭代器初始化过程中会将这个值赋给迭代器的 expectedModCount,
    则此时:modCount==expectedModCount==4。

     

    当我们对list修改,则modCount+1,此时,modCount==5

    expectedModCount依然为 4,

    因为:modCount != expectedModCount,所以抛出异常!
     

    注:

    所以我们使用迭代器来进行删除,因为迭代器可以维持这两个数相同,使用使用迭代器就不会出现像使用foreach这种情况的出现。

     

    • 迭代器删除01

          使用迭代器进行删除集合中的数据,首先不会存在数据想要删除的数据,没有被删除,或者多删,报错这种情况不会出现,使用迭代器不报错的原因,是因为迭代器可以维持那两个数的相等,所以不会像foreach出现那种情况。

    1. @Test
    2. public void test05() {
    3. Iterator<Integer> it=list.iterator();
    4. while(it.hasNext()) {
    5. Integer vaule=it.next();
    6. if(vaule==3) {
    7. it.remove();
    8. }
    9. }
    10. }

        得到的结果:[1, 2, 4, 5, 6] 

      

    • 迭代器删除元素02

        第二种使用迭代器的方法,但是这种方法咋就是一整个漏住,会直接报错。

        为什么报错嘞?

       迭代器其实在另外一个线程复制了一个一摸一样的集合进行遍历的。当用集合的remove方法删除元素时,迭代器是不会知道的,所以就会抛出异常。 

        

    1. @Test
    2. public void test06() {
    3. Iterator<Integer> it=list.iterator();
    4. while(it.hasNext()){
    5. Integer value=it.next();
    6. if(value==3){
    7. list.remove(value);
    8. }
    9. }
    10. System.out.println(list);
    11. }
    • list集合删除方法

        这句语句是删除下标为2的元素

    list.remove(2);

         这句是删除元素为2的

     

    list.remove(Integer.valueOf(2));

      四.LinkedList集合

    •  和List集合用法一样
    •  线程不安全
    • LinkedList集合实现双向链表接口,实现从头元素到尾元素的链表和从尾到头元素的链表,目标为了增加元素的检索效率 
    • 适合做随机的增加或者删除

    五.Vector集合 

    • 线程安全
    • Vector中所有的方法都是线程同步的,都带有synchronized关键字,所以他的并行性能慢,不建议使用

    为什么性能慢?

    打个比方,比如一个厕所有三个位置,有一个人去上厕所了,他就直接把最外面的那个门给关了,他一个人进去上厕所,但是他只需要一个位置,但是他把大门锁了,其他人只能在外面等待,结果他自己就上一个位置,其他两个都空着。也就是Vector进去一个他就会上锁,等里面执行完成,在到另外一个。也就是同步锁的一个原理。

    六.CopyOnWriteArrayList集合 

    • 线程安全,相比Veator性能更加好
    • 适合读多,写少的的场景
    • 写时复刻
    • 最终一致性

        CopyOnWriteArrayList集合写时复刻和最终一致性什么意思?

       CopyOnWriteArrayList集合这个集合,我觉得是非常有意思的,当我们需要对该数据进行操作时,他会将原本集合中的数据复制过去,然后在复制过去的集合里的元素进行操作,这就是写时复刻,等修改完成,这个修改过的集合就会给到原本的数组哪里,这是最终一致性。

     

     今天的学习就到这里啦!!!下篇文章为大家带来set集合的一个详细讲解。 

  • 相关阅读:
    网易雷火9.18笔试题
    医院职工离职申请证明模板,共计10篇
    猿创征文|Axios的介绍与作用 - 大白话
    MyBatis-Plus深入 —— 条件构造器与插件管理
    HCIP复习第二课:HCIA(网络类型及数据链路层协议)
    Liquid Studio 2023.2 Crack
    阿里云服务器部署wordpress站点
    大学生影视主题网页制作 腾龙电影网页设计模板 学生静态网页作业成品 dreamweaver电影HTML网站制作
    如何开发一款基于 Vite+Vue3 的在线表格系统(上)
    oppo r11 升级8.1系统 图文教程
  • 原文地址:https://blog.csdn.net/m0_65725031/article/details/125483564