ArrayList原理解析

ArrayList继承关系图

Iterable:

实现这个接口的类可以和增强for循环一起使用

// 返回这个类的迭代器
Iterator iterator();

Collection:

这个接口是所有集合的父接口,定义规范了所有集合的行为

public boolean add(E object);
public boolean addAll(Collection collection);
public void clear();
public boolean contains(Object object);
//判断collection是否全部在当前集合中
public boolean containsAll(Collection collection);
public boolean equals(Object object);
public boolean isEmpty();
public Iterator iterator();
public boolean remove(Object object);
// 去除当前集合中collection中的元素
public boolean removeAll(Collection collection);
// 在当前集合中保留collection中的元素(取交集)
public boolean retainAll(Collection collection);
public int size();
// 将这个集合中所有的数据当做数组返回
public Object[] toArray();

ArrayList:

ArrayList的底层是一个数组,特点是增删慢,查找快,线程不安全;
ArrayList类中的变量

// 底层数组的默认大小
private static final int DEFAULT_CAPACITY = 10;
// 存放数据的个数
int size;
// 底层数组对象
transient Object[] elementData;
// 一个空的数组,用来初始化上面的elementData对象
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

transient:transient关键字修饰的变量不参与序列化过程

ArrayList():
// 给array对象赋值一个空的数组
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

新建一个ArrayList对象,会为底层的数组赋值一个空的obj数组

add():
public boolean add(E e) {
        // 判断size+1是否超过数组容量,超过就扩容
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

    private void ensureCapacityInternal(int minCapacity) {
        // 如果elementData是第一次在构造方法中赋值的空数组,首次初始化10个大小
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        // 数组size改变的次数(存放在AbstractList中)
        modCount++;
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            // 如果当前需要的容量大于数组的实际容量,执行扩容逻辑
            grow(minCapacity);
    }

//  数组最大容量 , 一些jvm需要存放一些head words
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //  数组扩容核心代码
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 新容量等于旧容量的1.5倍
        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);
    }

    // 如果这次扩容的新大小大于数组最大值(max-8)
    private static int hugeCapacity(int minCapacity) {
        // 如果超过int的max,overflow
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        //  如果还没有超过max将新容量调整到max
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

add操作:在添加操作中,首先会判断当前size+1后是否超过底层数组的容量,如果是第一次add,将底层数组的容量默认扩容为10个大小,当第十一次添加的时候(需要的大小11>底层数组的大小10)进行扩容处理,新的底层数组大小变成旧数组的1.5倍,底层数组容量的最大值是max-8,但是如果超过这个数,还是能继续扩充到max的,当超过max就会溢出,OutOfMemoryError;

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

    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

get操作很简单,判断index是否合法,返回数组的第index个元素

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; // clear to let GC do its work

        return oldValue;
    }

remove操作调用了java的一个native方法,arraycopy(Object src, int srcPos, Object dest, int destPos,int length),各个参数的含义:

  • src:需要复制的数组
  • srcPos:src的开始下标
  • dest:返回的结果数组
  • destPos:dest的开始下标(从哪里开始复制)
  • length:复制的长度
    remove的思路是将下标index的元素丢弃,然后将index到size-1的元素通过arraycopy全部向前移动一个单位,将最后一个元素置为null等待gc回收
remove(Object o):
 public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }

remove(obj)通过循环找到obj对象的index,再通过index和arraycopy删除元素,fastRemove同上面的remove(index),只不过省去了保存obj的逻辑;

clear()
    public void clear() {
        modCount++;

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

        size = 0;
    }

简单易懂

你可能感兴趣的:(ArrayList原理解析)