美文网首页
【面试大纲】Java集合-ArrayList

【面试大纲】Java集合-ArrayList

作者: bearPotMan | 来源:发表于2019-12-03 21:51 被阅读0次

List

首先说一下list的一些特点:list中的元素是有序并且有重复的!
以下内容请结合源码一起食用效果更佳!

ArrayList

底层是什么?

ArrayList的底层是数组

初始化参数有哪些?

  • 默认容量是10
  • 当调用 new ArrayList(),即调用空的构造函数的时候是默认初始化一个空数组。然后往数组添加元素也即调用add(E)或add(int, E)方法的时候才初始化数组容量为默认值10;
  • 当调用 new ArrayList(int initialCapacity),即调用指定数组容量的构造函数的时候是默认初始化一个指定大小的数组;

扩容机制是怎样的?

  • 当添加新的元素的时候,如果size+1大于当前数组的容量,默认扩容为原数组容量的1.5倍,这个1.5倍的说法不是很严谨,源码中是 int newCapacity = oldCapacity + (oldCapacity >> 1);,也即原容量+原容量右移一位,可以理解为原容量+原容量/2(即对2取整的结果)。

是否线程安全?

ArrayList是非线程安全的!为什么?

  • 当不会触发扩容的时候,新元素添加到数组中的操作是elementData[size++] = e;,这里size++操作就不是线程安全的,因为它不是一个原子操作,多线程情况下很容易出现并发的问题!
  • 当触发扩容的时候,可能会出现数组元素丢失的情况,具体是怎么个丢失法呢?假设数组容量是10,现在有两个线程同时执行到grow()方法,在最后一步执行数组拷贝以及重复赋值时,两个线程都执行了数组的拷贝,然后A线程先赋值elementData = Arrays.copyOf(elementData, newCapacity);,接着完成了add方法,此时数组elementData[10]这个位置就添加量新的元素,然后B线程再进行数组的赋值,此时就会将A线程添加的元素值给覆盖掉的情况!这个过程好好想想还是可以理解的!

拓展: 如果想要使用线程安全的ArrayList有没有呢?
可选方案有:Vector、Collections.synchronizedList()、CopyOnWriteArrayList
小妙招:如果能确定ArrayList的初始容量,最好是使用new ArrayList(int initialCapacity)这个构造函数,避免数组扩容带来额外的影响。

使用场景有哪些?

ArrayList的一个特性就是它的底层是基于数组的,数组是一种线性数据结构,在内存中的存储空间是连续的。

  • 查询的效率高,因为空间连续,支持通过下标的随机访问;
  • 增删改的效率可能不是很好,因为要重新拷贝数组,当数组的元素特别多的时候,这个效率可想而知!

所以说,对于只是随机访问的,使用ArrayList是个不错的选择,效率高还安全!如果要执行一些增删改的操作,可以考虑使用LinkedList!
下一篇就说一下LinkedList!

彩蛋
多次执行下面的代码,看看有什么发现?

public class ArrayListUnsafeTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>(10);
        for (int i = 0; i < 5; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

相关文章

网友评论

      本文标题:【面试大纲】Java集合-ArrayList

      本文链接:https://www.haomeiwen.com/subject/ndzscctx.html