面试系列之集合ArrayList(一)

  集合是面试八股文之一,我今天开始就慢慢把这个集合类研究研究,主要从一些底层结构、使用方法和特性进行分析,没有太多的分析源码。

1、基本属性:

 1  /**
 2      * Default initial capacity.
 3      * 默认初始容量大小
 4      */
 5     private static final int DEFAULT_CAPACITY = 10;
 6 
 7     /**
 8      * Shared empty array instance used for empty instances.
 9      * 空数组实例
10      */
11     private static final Object[] EMPTY_ELEMENTDATA = {};
12 
13     /**
14      * Shared empty array instance used for default sized empty instances. We
15      * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
16      * first element is added.
17      *  默认容量的空数组实例
18      */
19     private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
20 
21     /**
22      * The array buffer into which the elements of the ArrayList are stored.
23      * The capacity of the ArrayList is the length of this array buffer. Any
24      * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
25      * will be expanded to DEFAULT_CAPACITY when the first element is added.
26      *    数组元素对象、用于存放list中的元素
27      */
28     transient Object[] elementData; // non-private to simplify nested class access
29 
30     /**
31      * The size of the ArrayList (the number of elements it contains).
32      *    添加的元素的数量
33      * @serial
34      */
35     private int size;

 

2、划重点:

  1. Arraylist的底层数据结构就是数组,默认的初始容量是10,但是前提是你调用空构造函数,没有指定初始大小且第一次添加元素的情况下,会自动扩容为10,若没有往里添加元素则还是0。如果有指定大小则以指定的为准,但是必须大于等于0,否则会抛出 IllegalArgumentException 异常提示 非法容量:xxx。

  2. 最小的扩容量是10,也就是第一次添加元素的时候会从0扩到10,直到添加第11个元素时才会调用grow方法,将当前数组扩容至原来的1.5倍。

  3. size 指的是数组的实际元素个数,而不是数组的大小

3、使用方法:

添加

1 arrayList.add( E element);
2 arrayList.add(int index, E element);
3 arrayList.addAll(Collection<? extends E> c);

删除

1 arrayList.remove(Object o);
2 arrayList.remove(int index)
3 arrayList.removeAll(Collection<?> c)

修改

1 arrayList.set(int index, E element)

查询

1 arrayList.get(int index);

清空

1 arrayList.clear();

判断是否存在

1 arrayList.contains(Object o);
2 arrayList.lastIndexOf(Object o);

4、特性:

1、有序、可重复

存入的Arraylsit的元素是有序的,且取出的时候可以按顺序取出,且存入的元素是可以有重复的

2、查找快、添加删除慢

查找快是因为arraylist是动态数组,长度可变,在内存中分配连续的空间,arraylist中的数据在内存中是连续的,查找的时候直接遍历内存就可以。增删慢是因为增加元素的时候,如果触发了扩容机制,则需要对整个数组进行复制,否则就是在数组中间添加删除的话,也会导致后面的元素移动,影响效率。

3、线程不安全

1  public boolean add(E e) {
2      // 校验是否扩容    
3         ensureCapacityInternal(size + 1);  // Increments modCount!!
4         elementData[size++] = e;
5      // 相当于 elementData[size] = e;size++;
6         return true;
7     }

假设此时size = 1,数组长度为1;

第一就是数据错误的情况,

线程一, elementData[1] = 1;,时间片结束了,需要等待下一个时间片;

线程二, elementData[1] = 2;,时间片结束了,需要等待下一个时间片;

线程一 size++ size = 2

线程二 size++ size = 3

所以 elementData[1] 的原始值别覆盖了,而elementData[2] 的值却赋值给了elementData[1] ,导致elementData[1] 的值不对,elementData[2]的值也不对且为空。

第二就是内存溢出的情况,

线程一,校验容量通过,时间片结束了,需要等待下一个时间片;

线程二,校验容量通过,时间片结束了,需要等待下一个时间片;

线程一,elementData[1] = 1 ,size++ ;( size = 2);

线程二,之前校验容量通过了,所以没有扩容,elementData[2] = 2,此时因为数组长度为1,所以内存溢出。

 

我了解的大概就这些,也不是很全面,如有不足或者错误,欢迎指教。

posted @ 2021-08-30 09:03  土豆GPT  阅读(170)  评论(0编辑  收藏  举报