美文网首页
ArrayList源码分析(二)

ArrayList源码分析(二)

作者: 一顆瓜子 | 来源:发表于2020-03-17 23:45 被阅读0次

当你停下来休息的时候,不要忘记,别人还在奔跑~

对上篇进行一个补充。。

1.ArrayList扩容Demo

getCapacity()方法通过反射获取ArrayList的容量。

public static Integer getCapacity(ArrayList list) {
        Integer lenth = null;
        Class c = list.getClass();
        Field field;
        try {
            field = c.getDeclaredField("elementData");
            field.setAccessible(true);
            Object[] o = new Object[0];
            try {
                o = (Object[]) field.get(list);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            lenth = o.length;
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return lenth;
    }

第一次初始化ArrayList

public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        Integer capacity = getCapacity(arrayList);
        System.out.println("容量:"+capacity);
        System.out.println("大小:" +arrayList.size());
    }
第一次初始化ArrayList.png

添加第一个元素的时候

public static void main(String[] args) {
        ArrayList<String> arrayList2 = new ArrayList<>();
        for (int i = 1; i <= 1; i++) {
            arrayList2.add("value" + i);
        }
        Integer capacity = getCapacity(arrayList2);
        System.out.println("容量:" + capacity);
        System.out.println("大小:" + arrayList2.size());
    }
添加第1个元素.png
将i改为9,添加第9个元素
添加第9个元素.png
将i改为11,添加第11个元素
添加第11个元素.png
将i改为16,添加第16个元素
添加第16个元素.png
将i改为23,添加第23个元素
添加第23个元素.png

综上:

当数组中添加第一个元素时,数组容量扩为10(默认值DEFAULT_CAPACITY=10)。直到Size+1大于数组容量时,就会去扩容,ArrayList 每次扩容之后容量确实变为原来的 1.5 倍左右(oldCapacity为偶数就是1.5倍,否则是1.5倍左右)! 奇偶不同,比如 :10+10/2 = 15, 15+15/2=22。如果是奇数的话会丢掉小数。

2.System.arraycopy() 和 Arrays.copyOf()方法

阅读源码的话,我们就会发现 ArrayList 中大量调用了这两个方法。比如:我们上面讲的扩容操作以及add(int index, E element)、toArray() 等方法中都用到了该方法!

 /**
     * 在此列表中的指定位置插入指定的元素。 
     *先调用 rangeCheckForAdd 对index进行界限检查;然后调用 ensureCapacityInternal 方法保证capacity足够大;
     *再将从index开始之后的所有成员后移一个位置;将element插入index位置;最后size加1。
     */
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //arraycopy()方法实现数组自己复制自己
        //elementData:源数组;index:源数组中的起始位置;elementData:目标数组;index + 1:目标数组中的起始位置; size - index:要复制的数组元素的数量;
        System.arraycopy(elementData, index, elementData, index + 1, size - index);
        elementData[index] = element;
        size++;
    }
   /**
     以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。 
     */
    public Object[] toArray() {
    //elementData:要复制的数组;size:要复制的长度
        return Arrays.copyOf(elementData, size);
    }
  • 联系:
    看两者源代码可以发现 copyOf() 内部实际调用了 System.arraycopy() 方法

  • 区别:
    arraycopy() 需要目标数组,将原数组拷贝到你自己定义的数组里或者原数组,而且可以选择拷贝的起点和长度以及放入新数组中的位置 copyOf() 是系统自动在内部新建一个数组,并返回该数组。

3.基本常识:

java 中的 length 属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了 length 这个属性.
java 中的 length() 方法是针对字符串说的,如果想看这个字符串的长度则用到 length() 这个方法.
java 中的 size() 方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!

LinkedList源码分析

相关文章

网友评论

      本文标题:ArrayList源码分析(二)

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