1.List是Java里边是一个接口,常见的实现的类是ArrayList和LinkedList,在开发中常用的是ArrayList
    2。ArrayList的底层的数据结构是数组,LinkedList底层数据结构是链表。
    3.Java本身就有数组了,为什么还需要用到ArrayList呢?
    4.原生的数组会有一个特点:你在使用时候必须要为他创建大小,而ArrayList不用。
    5.在日常的开发中,往往不知道要给数组分配多大的大小。
    6.如果数组的大小指定多了,内存浪费;如果数组大小指定小了,装不下。
    7.假设我们给定的数组的大小是10,要往这个数组中添加元素,我们只能添加10个元素。
    8.而ArrayList不一样,ArrayList我们在使用的时候可以往里面添加20个,30个元素,甚至更多的元素。
    9.因为ArrayList是实现了动态扩容的。
    10.大概的意思就是,当我们new ArrayList()的时候,默认会有一个空的Object数组,大小为0.
    11.当我们第一次add添加数据的时候,会给这个数组初始化一个大小,这个大小默认是10.
    12.使用ArrayList在每一次add的时候,它都会先去计算这个数组够不够空间。
    13.如果这个空间是足够的,那么直接追加上去,如果不够,那就得扩容。
    14.那怎么扩容?
    15.在源码里面,有个grow方法,每一次扩大原来的1.5倍,比如说,初始的大小是10,现在有第十一个元素进来了,发现空间不够,扩大到15.
    16.空间扩大后,会调用arrayCopy方法来进行数组的拷贝。
    17.为什么在日常中使用最多的是ArrayList呢?
    18.是由底层的数据结构来决定的,在日常的开发中,遍历的需求比增删要多,即便是增删也是往往在list的尾部添加就ok了,另外,ArrayList的增删的底层调用的copyOf()被优化过。现代的Cpu对内存可以块操作,ArrayList的增删一点也不会比LinkedList慢。
    19.vector有了解过吗?
    20.vector底层结构是数组,一般现在很少用了。
    21.相对于ArrayList,他是线程安全的,在扩容的时候他是直接扩容两倍。
    22.那如果我们不用vector,线程安全的list还有什么?
    23.首先,我们可以用Collections来将ArrayList来包装一下,变成线程安全。

    1. 线程安全ArrayListList<String> list = Collections.synchronizedList(new ArrayList());
    2. 线程安全LinkedListList<String> list = Collections.synchronizedList(new LinkedList());

    24.还有就是在java.util.concurrent包下还有一个类,叫做CopyOnWriteArrayList。这个类是一个线程安全的List,底层是通过复制数组的方式来实现的。
    25.简单说说CopyOnWriteArrayList的add()方法。在add方法的实现里,首先他会加lock锁,锁住,然后会复制出一个新的数组,往新的数组里面add真正的元素,最后把array的指向改变为新的数组。
    get方法又或是size()方法只是获取array所指向的数组的元素或者大小。
    26。CopyOnWriteArrayList有什么缺点?
    27.很显然,CopyOnWriteArrayList是很耗内存的,每次的set/add都会复制一个数组出来。另外,CopyOnWriteArrayList只能保证数据的最终一致性,不能保证数据实时一致性。
    28.怎么就不能保证数据实时一致性?
    29.假设两个线程,线程A去读取CopyOnWriteArrayList的数据,还没有读完。现在线程B把这个List给清空了,线程A此时还是可以把剩余的数据给读取到的。
    30.List和数组的最大的区别; 扩容机制;cow机制;CopyOnWriteArrayList实现原理。
    总结:

    1. list和数组的最大的区别?
    • 数组:内存中连续,索引速度快,不足:数组在两个数据之间插入数据麻烦,声明数组时候,必须指定数组的长度。(过大,浪费,过小,不够装)
    • ArrayList 是.net框架提供用于数据存储和检索的专用的类。按照存储的数据来动态的扩充和收缩。