ArrayList浅析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ErickPang/article/details/82693734

前一篇分析了HashMap,这篇分析ArrayList的机构和常用的方法,有不对的地方也希望大咖指正。
ArrayList是一个数组,一个可以动态扩容的数组,进入正题。

构造浅析

ArrayList中有自定义属性:

  • DEFAULT_CAPACITY:默认数组大小
  • EMPTY_ELEMENTDATA:一个空数组
  • elementData:存放数据的数组对象
  • size:数组大小

ArrayList提供了3中构造,指定数组大小,无参,指定Collection集合;

//第一种指定大小的构造
public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        //比较简单就是将数组按照指定的大小进行初始化
        this.elementData = new Object[initialCapacity];
}
//第二种默认构造
 public ArrayList() {
        super();
        //不指定大小则采用空数组初始化
        this.elementData = EMPTY_ELEMENTDATA;
}
//第三种构造指定集合
public ArrayList(Collection<? extends E> c) {
        //将指定集合转为数组
        elementData = c.toArray();
        //数组大小初始化
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        //若不是Object[],则转换。
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
}

三种构造比较简单对数据进行初始化。

set、add浅析

1、set方式,用指定的元素将指定位置的元素替换。

public E set(int index, E element) {
        //判断指定位置是否越界
        rangeCheck(index);
        //找到对应位置的元素
        E oldValue = elementData(index);
        //将新元素放如指定位置
        elementData[index] = element;
        //返回旧值
        return oldValue;
}

将新元素放到指定位置,并返回旧值。
2、add元素

public boolean add(E e) {
        //保证数据容量扩容,往下看
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将新元素放到数组中
        elementData[size++] = e;
        return true;
}
private void ensureCapacityInternal(int minCapacity) {
        //判断数组是否为空的,若为空的则传入的大小与默认值取大作为新数组大小
        if (elementData == EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        //往下看
        ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // overflow-conscious code
        //计算出来的数组大小比当前数据大小要大则进行扩容
        if (minCapacity - elementData.length > 0)
            //往下看
            grow(minCapacity);
}
private void grow(int minCapacity) {
        // overflow-conscious code
        //备份现有数组大小
        int oldCapacity = elementData.length;
        //增加当前大小的一半,oldCapacity >> 1相当于当前值右移1位,相当于除2^1
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //若扩容后的大小比出入的小,则采用传入的作为新的数组大小
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        //若新的数组大小比默认最大值大,则取int类型的最大值
        //MAX_ARRAY_SIZE =Integer.MAX_VALUE - 8
        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);
}
//比较简单不做介绍
private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

3、add(int index, E element)将元素放到指定位置

public void add(int index, E element) {
        //判断是否越界,跟上边一样
        rangeCheckForAdd(index);
        //跟add(E e)中一样
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        //将所有元素按照从index位置后移1个
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        //将新元素放到空出来的位置
        elementData[index] = element;
        size++;
}

get

 public E get(int index) {
        rangeCheck(index);
        return elementData(index);
}

验证是否越界,不越界直接获取指定位置元素返回。

remove浅析

数组的移动,将空余位置及其后的元素往前移动

public boolean remove(Object o) {
        //若删除的元素为null,则循环整个数组看是否有空余位置,如有则删除。
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            //若不为null,则找到指定位置,然后用其后元素覆盖
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
}
private void fastRemove(int index) {
        modCount++;
        //需要移动的元素个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            //将index+1位置及其后的numMoved个元素复制到index位置及其后numMoved
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
        //数组大小减1
        elementData[--size] = null; // clear to let GC do its work
}

总结

ArrayList比HashMap要简单,就是对数组的操作,以及数组拷贝。

猜你喜欢

转载自blog.csdn.net/ErickPang/article/details/82693734