转载

【源码解析】扒开ArrayList的外衣

积千里跬步,汇万里江河;每天进步一点点,终有一天将成大佬。

本文内容

当然ArrayList里的方法不止这些,本文主要讲一些常用的方法

【源码解析】扒开ArrayList的外衣

方法变量

Arraylist 里的方法变量主要有以下几个

【源码解析】扒开ArrayList的外衣

1. 构造方法

1.1 有参构造

1.1.1 传入数组的大小

1.1.1.1代码实现

List<String> list=new ArrayList<>(5);

1.1.1.2源码解析

【源码解析】扒开ArrayList的外衣

1.1.2 传入一个list对象

其实这个就相当于把传入的list对象里的数据 复制 到新的ArrayList对象

1.1.2.1 代码实现

List<String> list=new ArrayList<>(Arrays.asList("z","m","h"));

这里用来 Arrays 工具类里的 asList 方法,它的源码里是直接返回一个List,有兴趣的可以去看看,这里就不介绍了

1.1.2.2 源码解析

【源码解析】扒开ArrayList的外衣

1.2 无参构造

这个比较简单,直接赋值一个空数组

1.2.1代码实现

List<String> list=new ArrayList<>();

1.2.2源码解析

【源码解析】扒开ArrayList的外衣

2. add方法

add一般常用的有两个方法,一个就是 add(E e) 在尾部添加数据,一个就是 add(int index,E element) 在指定位置插入元素

2.1 add(E e)

这个是 Arrayist 的主要方法,平时用的也是最多的方法之一,所以源码比较复杂,比较长

2.1.1 代码实现

List<String> list=new ArrayList<>();
list.add("灰灰HK");

2.1.2 源码解析

【源码解析】扒开ArrayList的外衣

  • ensureCapacityInternal(int minCapacity) 确保数组容量充足

【源码解析】扒开ArrayList的外衣

  • calculateCapacity(Object[] elementData, int minCapacity)

【源码解析】扒开ArrayList的外衣

  • 再回到 ensureExplicitCapacity(int minCapacity) 这个方法,这个方法先 修改次数加1 ,然后判断 size+1 是不是比当前的数组容量大,如果比当前的数组容量大,则进行扩容操作,扩大容量为原数组的 1.5倍

比如第二次调用add方法,此时 size+1=2 , elementData.length=10 ,为什么等于10呢?因为第一次默认把数组容量从0扩大到了10,这时 size+1elementData.length 小,就不会进行扩容操作

【源码解析】扒开ArrayList的外衣

  • grow(int minCapacity) 扩容

这里调用 Arrays.copyOf() 方法进行复制操作,当进一步深入这个方法时,发现是由 System.arraycopy() 这个方法实现复制功能的,这个方法由 native 关键字修饰,表示不是由 Java 语言实现的,一般是c/cpp实现

【源码解析】扒开ArrayList的外衣

2.1.3 小结

到这里,add的方法流程就走完了,其核心步骤:

第一次
原大小的1.5倍
System.arraycopy()

2.2 add(int index, E element)

该方法为在指定位置插入元素,该位置及后面所有元素后移

2.2.1 代码实现

List<String> list=new ArrayList<>();
list.add("hk");
list.add(0,"灰灰");

2.2.2 源码解析

【源码解析】扒开ArrayList的外衣

可以看到,这边又用到了 System.arraycopy() 这个方法

  • rangeCheckForAdd(int index) 判断是否越界

这里他是和 size 对比,而不是和数组的 length 对比,我个人认为这样第一节省了空间,第二方便后面移动的操作

【源码解析】扒开ArrayList的外衣

  • System.arraycopy() 拷贝数组
public static native void arraycopy(Object src,  int  srcPos,
                                     Object dest, int destPos,
                                    int length)
  • src 原数组对象
  • srcPos 原数组起始位置
  • dest 目标数组
  • destPos 目标数组起始位置
  • length 复制多少个数据

2.2.3 小结

插入方法其主要步骤如下:

  • 检查插入的位置是否越界
  • 检查数组容量是否充足,不充足进行扩容相关操作
  • 调用 System.arraycopy() 进行 index 及后面的元素后移

3. get方法

3.1 get(int index)

3.1.1 代码实现

List<String> list=new ArrayList<>();
list.add("hk");
list.get(0);

3.1.2 源码解析

【源码解析】扒开ArrayList的外衣

  • rangeCheck(int index) 判断是否越界

get个add方法判断越界的方法是不一样的,这边是 index>=size ,多了个 等于 ,为什么要多个等于呢?因为数组是从0开始的,而size 相当于 是开始的从1开始的

private void rangeCheck(int index) {
    if (index >= size)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
  • elementData(int index) 直接返回对应下标的数组元素
E elementData(int index) {
    return (E) elementData[index];
}

3.1.3 小结

get方法比较简单,主要步骤为:

  • 检查是否越界
  • 返回对应元素

4. set方法

4.1 set(int index, E element)

4.1.1 代码实现

List<String> list=new ArrayList<>();
list.add("hk");
list.set(0,"灰灰");

4.1.2 源码解析

【源码解析】扒开ArrayList的外衣

5. remove方法

5.1 remove(int index)

5.1.1 代码实现

List<String> list=new ArrayList<>();
list.add("hk");
list.remove(0);

5.1.2 源码解析

当删除的元素为最后一个元素时, numMoved 就小于0了,就不会进行移动元素的操作

【源码解析】扒开ArrayList的外衣

5.2 remove(Object o)

这个方法在实际中用的比较少,因为 AraryList 是可以保存重复的元素,所以删除是 删除最早添加的元素

5.2.1 代码实现

List<String> list=new ArrayList<>();
list.add("hk");
list.remove("hk");

5.2.2 源码解析

【源码解析】扒开ArrayList的外衣

  • fastRemove(int index) 删除元素

这个方法和remove(int index)内部的操作类似,不过这边不保存被删除的元素

private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

6. clear方法

6.1 clear()

6.1.1 代码实现

List<String> list=new ArrayList<>();
list.add("hk");
list.clear();

6.1.2 源码分析

【源码解析】扒开ArrayList的外衣

总结

ArrayList 底层扩容或者移动数组元素时都调用了 System.arraycopy() 来进行相关操作,平时进行我们进行数组复制或移动的时候也可以调用这个方法了,这个性能比循环复制性能高多了,特别是在大量数据的时候。

文章好几次出现了 modCount++ 这个操作,这个 modCount 主要用户内部类的迭代器

原文  https://segmentfault.com/a/1190000021482778
正文到此结束
Loading...