java 容器(collection)--ArrayList 常用方法分析 源码分析

ArrayList 介绍

打开jdk源码看看官方文档的介绍

在这里插入图片描述
粗糙的翻译下大致意思是:
List接口的可调整大小的数组实现。实现了所有可选的列表操作,并允许所有元素,包括 null 。除了实现List接口之外,这个类提供了操作数组大小的方法。

ArrayList定义的属性

 /**
     * 默认容量大小10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空构造器调用
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 缓冲区
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * 元素个数
     */
    private int size;

无参构造器

  /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

这个相当于创建一个空数组:
this.elementData={};

有参构造器

/**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    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);
        }
    }

他的健壮性比较好,我们按正常思维,只看第一个 initialCapacity > 0 的 if 分支:
相当于创建一个长度为 20 的数值:
this.elementData=new Object[20];

添加方法 add(Object obj)

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

这个代码技术含量挺高,不愧是老司机写的
ensureCapacityInternal(size + 1); 用来 检测空间容量是否够用(看下一个方法)
elementData[size++] = e; 就是添加元素相当于:
elementData[size]=e; size++;

检测空间容量是否够用

 private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

这个方法首先会在内部调用calculateCapacity(elementData, minCapacity) 计算容量:

private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

当我们在新建一个ArrayList 对象上添加元素时:
Math.max(DEFAULT_CAPACITY, minCapacity); 相当于:
Math.max(10,1);

到这里容量计算完了,然后回去执行:

 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

由于是第一次添加,if 条件相当于:
if( 10 - 0 > 0)
结果为true,会执行if语句块
grow(minCapacity); 执行的就是扩容方法。

扩容方法

 private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

我们是第一次添加,以上代码实际执行的就是:
int oldCapactiy=0;
int newCapacity=0+0>>1 结果为0
如果 0-10<0 为 true
newCapacity=10;
数组拷贝 elementData的长度就是 10

最后回到:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
结果就是:
elementData[0] = e;
size++;

接下来看下add 的重载方法

add(int index, E element)

public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }

rangeCheckForAdd(index);是下标越界检测,我们先不看,下一行代码:
ensureCapacityInternal(size + 1);跟之前的默认位置天机一样先检测数组的空间容量。
关键是再往下一行代码;
执行的结果是把要插入位置开始到结束的所有元素往后挪一个位置,然后把空出的位置赋值为传入有的参数,同时把元素个数+1;

现在ArrayList对象的容量是10了,当我么一直做添加操作,容量满了会怎么样呢?
其实不管我们怎么添加,都会执行ensureCapacityInternal(size + 1) 来检测容量,而ensureCapacityInternal(size + 1)又会调用calculateCapacity(elementData, minCapacity)直到
ensureExplicitCapacity(int minCapacity)方法中的if语句成立时,执行
grow(minCapacity);进行扩容:
比如我们加到第11个元素时:
grow(minCapacity)方法中的
oldCapacity + (oldCapacity >> 1);返回15;
那么ArrayList的容量就增加到15了;
继续增加还是一样的操作。
至此,我们已经对ArrayList 创建,添加,扩容有了一定了解。
那么剩下的一些方法就是数组的操作了,很好理解。

ArrayList的其他方法

get(int index)根据索引获取元素对象

public E get(int index) {
        rangeCheck(index);
		//调用了elementData()的方法
        return elementData(index);
    }
 @SuppressWarnings("unchecked")
    E elementData(int index) {
    	//根据索引取出数组中索引对象
        return (E) elementData[index];
    }

size()

  public int size() {
  		// 返回集合记录的元素个数
        return size;
    }

isEmpty()

public boolean isEmpty() {
	// 这个太简单了,不必多说
        return size == 0;
    }

set(int index, Object obj)

public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

就是数组操作,返回替换掉的元素

remove(int index)

 public E remove(int index) {
        rangeCheck(index);

        modCount++;
        //根据索引获取原始元素对象
        E oldValue = elementData(index);
        //拷贝的元素的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; //   将最后一个位置设置为null

        return oldValue;
    }

类似于前面的指定位置添加,返回原始元素对象

clear()

public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

循环遍历,所有 索引位置的元素赋值null,并把元素个数设置为0;

水平有限,先写到这了。

posted @ 2020-03-21 18:14  行者老夫  阅读(151)  评论(0编辑  收藏  举报