ArrayList优点:
- 随机读性能很高,因为底层是基于数组实现,可以通过get(i)寻址快速读取
- 获取元素个数性能很高
- arrayLis天生按元素插入顺序排序
ArrayList缺点: - 在扩容时需要从旧数组把元素拷贝到新数组,性能很差
- 在随机插入时会导致插入点之后的元素在数组中移动,性能也很差
ArrayList使用场景及使用注意事项: - 在new ArrayList时最好根据业务场景进行容量的初始化,避免在之后的Add操作时触发数组的扩容,进而提高使用性能
- 如果有频繁的add(i,e)的操作则不建议使用
- ArrayList最好使用在一次性add,之后都是读的场景
- ArrayList的元素天生可以重复,所以需要去重的场景不适合
ArrayList主要方法解析:
ArrayList构造器: - 无参构造器:ArrayList();
构造一个空的数组 - ArrayList(int initialCapacity)
按照给定容量大小初始化一个数组 - ArrayList(Collection<? extends E> c)
根据给定集合进行初始化数组
使用建议:最好不用使用无参构造器,应该根据业务场景给定容量大小,这样可以避免在后续的add环节频繁的扩容以及新旧数组间的元素拷贝
add(E e)方法:在数组的size+1位置放入元素 - 检查是否需要数组扩容
a. 计算需要的最小容量大小:calculateCapacity方法
i. 如果当前数组是默认的空数组则使用默认容量也就是10,否则就是当前元素size+1
b. 如果计算出来的需要的容量大小大于当前数组大小则需要扩容 - 扩容:grow(miniCapacity)
a. 新数组长度的计算
i. 新数组长度默认是旧数组长度的1.5倍(int newCapacity = oldCapacity + (oldCapacity >> 1);
ii. 如果旧数组长度的1.5倍小于miniCapacity,则新数组长度取miniCapacity
iii. 如果miniCapacity大于MAX_ARRAY_SIZE长度,则取Integer的最大长度
b. 把旧数组的元素拷贝到新数组中(Arrays.copyOf(elementData, newCapacity)),底层使用的System.ArrayCopy方法 - 在数组的size+1位置放入e元素elementData[size++] = e;
使用建议:这个方法在ArrayList中是最常用的,在整个过程中可以看出如果使用无参构造器第一次add就会进行数组扩容,初始化容量大小是10,每次扩容以旧容量的1.5倍进行。这个方法的性能瓶颈也就在这个过程中了
add(int index,E e)方法:在数组的index位置放入元素 - 检查index是否超过数组大小,超过则报错
- 检查是否需要扩容以及需要的话进行扩容
- 把index位置及之后的元素都往后移一个位置
- 在数组index位置上放入e元素
- size++
使用建议:这个方法性能瓶颈在第二步和第三步(扩容和数组元素的移动),所以这个方法不建议使用,而且在真正的生产中也是几乎不用的
addAll(Collection c)方法:把集合c中的元素都加上数组中 - 检查是否需要扩容以及需要的话进行扩容
- 通过System.arrayCopy把c中的元素都拷贝到数组中
set(int index,E e)方法:在数组的index位置放入元素
6. 检查index是否超过数组大小,超过则报错
7. 拿出index位置的元素,在之后返回
8. 在数组index位置放入元素
使用建议:这个方法非常不常用, 也没有优缺点
get(int index)方法:获取数组的index位置元素
简单不说了
remove(int index)方法:删除数组的index位置元素
通过数组元素的移动覆盖index位置的元素,然后置空s数组ize-1位置达到删除的目的。
remove(Object o)方法:删除数组中指定元素
通过遍历数组找到o元素所在的index,再 通过数组元素的移动覆盖index位置的元素,然后置空s数组ize-1位置达到删除的目的。
iterator()方法:迭代ArrayList中的元素
会new Itr()的一个内部类,通过游标cursor进行遍历,需要注意的是如果在遍历的过程中增加或删除元素会导致报ConcurrentModificationException
subList(int fromIndex,int toIndex):生成子List
会new SubList()的一个内部类,这个内部类具有ArrayList中的所有方法,而且所有方法操作的数组还是之前ArrayList中的数组。
欢迎关注公众号——java面试工程师