ArrayList创建新集合源码剖析

ArrayList简介

      ArrayList的顶层是数组队列,相当于动态数组。与数组相比,数组的长度是固定不可变的,但集合可以动态扩容。在添加大量元素前,应用程序可以使用ensureCapacity()方法来操作增加当前集合的容量,这样可以坚持少递增式再分配数量。ArrayList继承于AbstractList,实现了 List, RandomAccess, Cloneable, java.io.Serializable 这些接口。

ArrayList创建新集合

  1. 创建一个空ArrayList集合的时候,源码中会调用一个默认的空数组创建该集合,源码:this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA ,而elementData定义的是个Object[ ],而DEFAULTCAPACITY_EMPTY_ELEMENTDATA则直接定义为{}空的数组,初始的ArrayList集合是没有长度的
  2. 空集合的长度是0,只有当往空集合中使用add()方法添加元素的时候,才会进行扩容
    源码:public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }   add()方法中先调用了 ensureCapacityInternal(size + 1)方法,此时的size则是0,传入的参数即1,我们再看看ensureCapacityInternal()方法的源码:
    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }这个方法中调用的ensureExplicitCapacity()方法就是ArrayList的核心方法,得到最小的扩容量,该方法中调用了calculateCapacity()方法,源码:
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    },判断了当前集合是不是一个空集合,如果是,则在默认集合大小和最小扩容大小和需要的最小长度中取最大的扩容量,我的理解是ArrayList如果元素小于10则只在第一次进行扩容,后面大于默认长度的时候则会根据每次计算的扩容需要的量来进行扩容。
    ensureExplicitCapacity的源码:
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
    
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }当拿到扩容量计算值之后和当前集合长度相比,如果扩容长度大于当前长度,那么就调用grow()方法进行扩容,否则不需要扩容
  3. 使用带参构造方法创建ArrayList的时候,参数为int类型的值,源码中会判断该参数的值,先看下源码:
  public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
},当传入的参数大于0的时候,那么会创建一个指定大小的数组创建集合,如果传入的参数=0,那么就会创建一个空的数组创建集合,如果传入负数,想当然会报错,因为数组长度没有负数。

    4.使用带参构造方法创建ArrayList的时候,参数为另外一个集合,源码中会判断该参数的值,先看下源码: 

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
},当传入的参数是一个集合的时候,首先会使用toArray()方法将该集合转为数组,判断转换后的集合长度是否等于0,如果不等于0,
且参数类型不是object[].class相等,那么会中用数组的copyOf方法拷贝一个参数传递的数组,类型设置为object[].class。如果转换后的集合长度是否等于0,那么就直接创建一个空的数组作为集合保存数据。

突然看到集合方面到问题,也没有详细看过源码,对于集合到创建不了解,今天没事就把自己理解的东西写出来,有什么错误的,希望大牛指出来,加以改正

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章