• ArrayList


    一. 存储特性

    • 有序且可重复

    1.为什么有序,且可重复??

    • ArrayList底层是Object数组,数组是有序的,所以有序;
    • 并且在执行添加的时候,底层并未对值做任何判断,而是直接添加,所以可重复

    2. 该集合底层是数组,那么该数组初始长度是多少??

    • JDK1.6之前,底层数组长度为10;
    • 之后,底层数组初始长度为0

    3. 如何入手查看源码??

    (1) 看核心属性

    • private static final int DEFAULT_CAPACITY = 10;
      • 默认数组大小
    • private static final Object[] EMPTY_ELEMENTDATA = {};
      • 空数组
    • private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
      • 默认空数组
    • transient Object[] elementData;
      • 底层存储元素的数组
    • private int size;
      • 集合存储的元素个数

    (2) 看核心构造器

    • public ArrayList() {
      this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
      }
      • 无参创建集合,底层用默认空数组直接指向底层数组
    • public ArrayList(int initialCapacity) {
      if (initialCapacity > 0) {
      this.elementData = new Object[initialCapacity];
      } else if (initialCapacity == 0) {
      this.elementData = EMPTY_ELEMENTDATA;
      } else {
      throw new IllegalArgumentException("Illegal Capacity: "+
      initialCapacity);
      }
      }
      • 有参创建集合,指定底层数组初始大小
      • 实参大于0,指定初始大小创建数组,指向底层数组
      • 实参等于0,直接用空数组,指向底层数组

     (3) 看核心方法

    • 按流程进入

     

     

     4. ArrayList的扩容原理是怎么样的,是怎么进行过扩容的???

    • 把原来(旧)的数组中的数据复制到一个新的,且内存空间更大数组中
    • 再将元素添加数组中

    5. ArrayList为什么是线程安全的还是不安全的???

    • 首先该集合是线程不安全
    • 其底层对于主方法没有加锁
    • 所以会出现多线程导致的数据丢失问题
    • 举例:
      • 因为底层主方法没有锁
      • 所以会出现A.B线程因CPU调度原因,都在第一次扩容时,进入了扩容方法,
      • 两者也执行完扩容方法,准备添加元素,此时size为0;
      • 此时A开始添加完元素,还未及时进行size++
      • CPU调度到了B线程,此时size还是0,所以B线程将索引为0的A元素给替换掉了
      • 就导致A数据丢失的问题

    6. 如何避免ArrayList集合的并发,线程安全问题

    • 方法一: 使用Collections.synchronizedList()方法对ArrayList对象进行包装
      • ArrayList<Integer> arraylist = Collections.synchronizedList(new ArrayList());
      • 此方法对SynchronizedList源码主要方法中都加了synchronized锁,保证单线程执行
      • 但是这个锁的力度很大,效率比较低
    • 方法二: 使用并发容器CopyOnWriteArrayList
      • CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<Integer>();
      • 此方法使用了Lock锁,对源码主要方法中都加了锁,保证单线程执行

    7. ArrayList的优缺点,以及什么情况下使用该集合???

    • 优点: 因为有索引,所以可以随机访问元素效率高
    • 缺点: 因为是有序的,所以增删麻烦,效率低
      •   增删时,因为需要整体元素进行移位,会不断进行ArrayCopy到新数组,非常消耗时间
    • 如果访问元素更频繁的话,建议使用ArrayList
    • 如果插入修改元素比访问元素更频繁的话,建议使用LinkedList

    8. 如何复制某个ArrayList到另一个ArrayList中去??

    • 第一种: 使用clone()方法,比如ArrayList newArray = oldArray.clone();
    • 第二种: 使用ArrayList构造方法,比如:ArrayList myObject = new ArrayList(myTempObject);
    • 第三种: 使用Collections的copy方法

    9. ArrayList,Vector和LinkedList的区别??

    • ArrayList线程不安全,底层为数组,增删慢,查找快,可通过Collections.synchronizedList()实现线程同步
    • LinkedList线程不安全,底层为链表,增删快, 查找慢,可通过Collections.synchronizedList()实现线程同步
    • Vector线程安全,增删慢,查找快

    10. 如下代码有什么问题? 能正常运行吗?? 如何解决??

     1  ArrayList<String> array = new ArrayList<>();
     2         array.add("aa");
     3         array.add("cc");
     4         array.add("bb");
     5         array.add("ee");
     6         array.add("ff");
     7 
     8         //CopyOnWriteArrayList<String> copyOnWriteArrayList =new CopyOnWriteArrayList(array);
     9 
    10         for (String o : array) {
    11             if("bb".equals(o)){
    12                 array.remove(o);
    13             }
    14         }

    • 首先数据少有时候可以正常运行
    • 但是大部分情况会报错,出现JUC并发修改异常
    • 调用remove()方法导致迭代器modCount和expectedModCount的值不一致。就会出现并发修改异常

    解决方案:

    • 普通for循环,倒叙遍历删除
    • 使用CopyOnWriteArrayList
  • 相关阅读:
    在ACCESS中LIKE的用法
    pip 在windows下的更新升级
    NAS、SAN、DAS 说明
    RAID 工作模式
    Linux mail 邮件发送
    Linux 邮件服务搭建
    HA 脑裂原理
    Tomcat 工作原理
    Nagios 工作原理
    Nginx 工作原理
  • 原文地址:https://www.cnblogs.com/bin563597293/p/14353603.html
Copyright © 2020-2023  润新知