ArrayList相关面试题

ArrayList与LinkedList的区别

  1. 线程安全:两者都不保证线程安全。如果需要线程安全的可以使用:

线程安全解决办法 :
方法1: Collections.synchronizedList(new LinkedList())
方法2: LinkedList和ArrayList换成线程安全的集合,如CopyOnWriteArrayList,ConcurrentLinkedQueue…
方法3:Vector(内部主要使用synchronized关键字实现同步)

  1. 底层数据结构:ArrayList底层数据结构是Object数组。LinkedList的是双向链表(1.6及之前使用的是循环链表)。
  2. 插入和删除操作的时间复杂度不同:
    ArrayList的底层是数组存储。插入和删除元素的时间复杂度受元素位置的影响。如果没有指定位置默认加入到链表尾部,为O(1),如果是指定加入到 i 位置则为O(n-i)
    LinkedList底层是链表,在插入和删除元素时间复杂度不受元素位置影响近似于O(1),如果插入到指定位置是O(n)。
  3. 是否支持快速访问:LinkedList不支持,ArrayList支持,因为底层是数组。
  4. 内存空间占用情况:ArrayList的内存占用在相同情况下小于LinkedList。ArrayList的内存占用主要在于尾部没有存储数据时。而LinkedList的内存每个元素需要额外存储前驱结点和后继结点。

RandomAccess接口

  1. RandomAccess接口什么也没定义。只是作为一个标识符。标识实现这个接口的类具有随机访问的功能。
  2. 如:在binarySearch()方法中,他被用来判断传入的list是否RandomAccess实例,如果是,调用indexedBinarySearch()方法,如果不是,那么调用iteratorBinarySearch()方法。
  3. 实现了RandomAccess的list,优先遍历的方式是for循环,然后再是foreach(foreach底层是iterator实现的)。没有实现的优先选择iterator。
  4. 对于ArrayList就实现了该接口而LinkedList没有实现。因为ArrayList的底层是数组,数组天然支持随机访问,时间复杂度为O(1)。而LinkedList底层是链表不能随机访问,只能从头指针处进行遍历。

ArrayList与Vector区别,为什么用ArrayList取代Vector

  1. Vector类的所有方法都是同步的,如果仅仅是一个线程去操作的话,就会消耗很多的时间在同步操作上。
  2. ArrayList不是同步的,所以在不需要保证线程安全的情况下使用ArrayList更好。

ArrayList的扩容机制

ArrayList有三种构造方法
第一种:不含参数的默认构造方法
public ArrayList()
第二种:带初始容量参数的构造函数(用户可自己指定容量)
public ArrayList(int initialCapacity)
第三种:构造包含指定collection元素的列表。
public ArrayList(Collection<? extends E> c)

  1. 在使用无参构造的时候,会初始化一个空数组。当真正的添加元素的时候才给数组真正的分配容量。即使用add(E e)方法时,才会将数组容量扩充为10.

具体过程: 当我们要 add 进第1个元素到 ArrayList 时,elementData.length 为0 (因为还是一个空的 list),因为执行了 ensureCapacityInternal() 方法 ,所以 minCapacity 此时为10。此时,minCapacity - elementData.length > 0 成立,所以会进入 grow(minCapacity) 方法。
当add第2个元素时,minCapacity 为2,此时e lementData.length(容量)在添加第一个元素后扩容成 10 了。此时,minCapacity - elementData.length > 0 不成立,所以不会进入 (执行)grow(minCapacity) 方法。
添加第3、4···到第10个元素时,依然不会执行grow方法,数组容量都为10。
直到添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进入grow方法进行扩容。
ArrayList 每次扩容之后容量都会变为原来的 1.5 倍左右(oldCapacity为偶数就是1.5倍,否则是1.5倍左右)! 奇偶不同,比如 :10+10/2 = 15, 33+33/2=49。如果是奇数的话会丢掉小数.

最好在 add 大量元素之前用 ensureCapacity 方法,以减少增量重新分配的次数
更详细的源码解读

参考:JavaGuide

猜你喜欢

转载自blog.csdn.net/H1517043456/article/details/107535721