集合ArrayList的实现

ArrayList 是 Java 集合框架中 List接口 的一个实现类。

可以说 ArrayList 是我们使用最多的 List 集合,它有以下特点:

  • 容量不固定,想放多少放多少(当然有最大阈值,但一般达不到)

  • 有序的(元素输出顺序与输入顺序一致)

  • 元素可以为 null

  • 效率高 

    • size(), isEmpty(), get(), set() iterator(), ListIterator() 方法的时间复杂度都是 O(1)

    • add() 添加操作的时间复杂度平均为 O(n)

    • 其他所有操作的时间复杂度几乎都是 O(n)

  • 占用空间更小 

    • 对比 LinkedList,不用占用额外空间维护链表结构

/*

*ArrayList基础AbstractList(其实类似的绝大部分多会继承一个抽象的类,此类实现一个接口,这是多态的一种表现,模式的一种应用:个人还不成熟观点)

/

public class ArrayList<E> extends AbstractList<E>

implements List<E>, RandomAccess, Cloneable, java.io.Serializable

 

ArrayList 的成员变量

/**

* 默认初始容量.注意:只用当使用add()方法的时候才会进行默认容器大小10;

*/

private static final int DEFAULT_CAPACITY = 10;



/**

* 用于共享的空的实例,由于是object说明其可以存储null

*/

private static final Object[] EMPTY_ELEMENTDATA = {};



/**

* 用于设定默认大小的共享的空的实例

* 与 EMPTY_ELEMENTDATA 进行区分开来,以方便何时设定大小

*/

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};



/**

* 正在存放集合元素的地方

*/

transient Object[] elementData; // non-private to simplify nested class access



/**

* ArrayList的当前个数

*/

private int size;

// 集合能存放的最大的数量(莫方 20多亿了)

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

 

ArrayList 的关键方法

1.构造函数

ArrayList 有三种构造函数:

/**

* 指定初始化容器的大小

*/

public ArrayList(int initialCapacity) {//initialCapacity 初始化容器大小值

    if (initialCapacity > 0) {

        this.elementData = new Object[initialCapacity];

    } else if (initialCapacity == 0) {

        this.elementData = EMPTY_ELEMENTDATA;

    } else {

        throw new IllegalArgumentException("Illegal Capacity: "+

        initialCapacity);

    }

}



/**

* 默认是一个空的object数据

*/

public ArrayList() {

    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;

}



/**

*将Collection类型的c转成ArrayList,并实例化

*/

public ArrayList(Collection<? extends E> c) {

    elementData = c.toArray(); // 将c转换为数组

    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;

    }

}

2.添加元素:

/**ArrayList的添加方法,使用add(),如果没有设定默认容器大小,会自动设定默认的大小为10

*/

public boolean add(E e) {

    ensureCapacityInternal(size + 1); // 用于判断容器的大小,是否针对性的进行扩容

    elementData[size++] = e;

    return true;

}

/*

*在指定的位置添加对应的element对象

/

public void add(int index, E element) {

    rangeCheckForAdd(index); // 判断在index位置添加值是否合法



    ensureCapacityInternal(size + 1); // 是否进行针对性的扩容;

    System.arraycopy(elementData, index, elementData, index + 1,

    size - index); //间element放入index的位置,后面的参数全部后移一位.

    elementData[index] = element;

    size++;

}

/**

*添加一个对应Collection类型的集合

*/

public boolean addAll(Collection<? extends E> c) {

    Object[] a = c.toArray(); //将c全部转换为数组

    int numNew = a.length; //获取c的数量

    ensureCapacityInternal(size + numNew); // Increments modCount

    System.arraycopy(a, 0, elementData, size, numNew);

    size += numNew;

    return numNew != 0;

}



/* 

* 在指定的index开始添加一个对应Collection类型的集合

*/

public boolean addAll(int index, Collection<? extends E> c) {

    rangeCheckForAdd(index);



    Object[] a = c.toArray();

    int numNew = a.length;

    ensureCapacityInternal(size + numNew); // Increments modCount

    // 将集合从index位置总体后移移动

    int numMoved = size - index;

    if (numMoved > 0)

        System.arraycopy(elementData, index, elementData, index + numNew,

        numMoved);

    //将集合从0重新进行放置

    System.arraycopy(a, 0, elementData, index, numNew);

    size += numNew;

    return numNew != 0;

}

3.添加元素过程中用到的方法,主要是如何对集合进行扩容

/*

*判断index是否下标越界

*/

private void rangeCheckForAdd(int index) {

    if (index > size || index < 0)

    throw new IndexOutOfBoundsException(outOfBoundsMsg(index));

}

/*

*对容器进行判断,是否进行扩容

*/

private void ensureCapacityInternal(int minCapacity) {

    //判断此时的集合是否是初始化状态,也就是还没有一次使用添加功能

    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {

       /** 主要针对的是初始化时使用的是add(),还是addAll()方法,针对请进行容量的定义

        *在初始化时add()肯定用DEFAULT_CAPACITY,但无法保证初始化时addAll()的实例不大于DEFAULT_CAPACITY 

        *DEFAULT_CAPACITY  = 10

        */

        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;

    int newCapacity = oldCapacity + (oldCapacity >> 1);

    if (newCapacity - minCapacity < 0)

        newCapacity = minCapacity;

    if (newCapacity - MAX_ARRAY_SIZE > 0) //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; MAX_ARRAY_SIZE反正非常大

        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;

}



/*

* 主动给集合设定容量大小

*/ 

public void ensureCapacity(int minCapacity) {

    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)

    // any size if not default element table

    ? 0

    // larger than default for default empty table. It's already

    // supposed to be at default size.

    : DEFAULT_CAPACITY;



    if (minCapacity > minExpand) {

        ensureExplicitCapacity(minCapacity);

    }

}

4.删除

/*

* 根据序号移除

*@return 被移除的对象 

*/

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; //由于用后面的覆盖,所以最后一个是没有remove前的数据,为null;



    return oldValue;

}



/**

* 根据对象移除

*/

public boolean remove(Object o) {

    if (o == null) {

        for (int index = 0; index < size; index++)

            if (elementData[index] == null) {

                fastRemove(index); // 与public E remove(int index)方法类似 

                return true;

            }

    } else {

        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)

        System.arraycopy(elementData, index+1, elementData, index,

        numMoved);

    elementData[--size] = null; // clear to let GC do its work

}



/*

* 移除Collection类型中c中的元素

*/

public boolean removeAll(Collection<?> c) {

    Objects.requireNonNull(c); // 判断是否为空

    return batchRemove(c, false);

}



private boolean batchRemove(Collection<?> c, boolean complement) {

    final Object[] elementData = this.elementData; //获取本集合的所有元素

    int r = 0, w = 0;

    boolean modified = false;

    try {

        for (; r < size; r++) //提取所有与c不相同的元素从0重新覆盖elementData

            if (c.contains(elementData[r]) == complement)

                elementData[w++] = elementData[r];

    } finally {

         /*此处只有当try中有异常才会执行;

         *将对比的元素,w前的和由于异常中断没有进行对比到的数据保存

         *很有价值观的设定!!!!

         */   

        if (r != size) {

            System.arraycopy(elementData, r,

            elementData, w,

            size - r);

            w += size - r;

    }

    if (w != size) {

        // 将w后的元素设为null,w前面的元素是与c对象不同的元素,从新定义集合的大小为w;

        for (int i = w; i < size; i++)

            elementData[i] = null;

            modCount += size - w;

            size = w;

            modified = true;

        }

    }

    return modified;

}

/**

* 移除集合,也就是把所有的值转为null

*/

public void clear() {

    modCount++;



// clear to let GC do its work

    for (int i = 0; i < size; i++)

        elementData[i] = null;



    size = 0;

}

/*

* 

*/

public Object clone() {

    try {

        // 克隆 元素本身是不会被复制的,只是引用的元素的地址

        ArrayList<?> v = (ArrayList<?>) super.clone();

        v.elementData = Arrays.copyOf(elementData, size);

        v.modCount = 0; // 该集合修改,添加等方法的操作次数为空

        return v;

    } catch (CloneNotSupportedException e) {

        // this shouldn't happen, since we are Cloneable

        throw new InternalError(e);

    }

}



//返回第index个元素

E elementData(int index) {

    return (E) elementData[index];

}

删除的方法比较慢,常常要移动的数据比较的,从新放置数据,并且使用循环判断删除或替代的时候要使用迭代器,用for会造成并发修改异常

5.获取,修改等;

/* 都较为非常,本质是对数组的操作

*获取指定下标的元素

*/

public E get(int index) {

    rangeCheck(index);



    return elementData(index);

}



/* 

*将指定的index下标,修改为element

*返回的是被修改的元素

*/

public E set(int index, E element) {

    rangeCheck(index);



    E oldValue = elementData(index);

    elementData[index] = element;

    return oldValue;

}

 

6.一些集合的状态判断等:

/*

* 获取集合元素的多少

*/

public int size() {

    return size;

}

/*

* 判断集合是否为空

*/

public boolean isEmpty() {

    return size == 0;

}



/* 

* 用于判断该有元素是否存在集合中

*/

public boolean contains(Object o) {

    return indexOf(o) >= 0;

}



/* 

* 从开头判断该元素是否存在,最开始出现的地方index

*/

public int indexOf(Object o) {

    if (o == null) { 

        for (int i = 0; i < size; i++)

        if (elementData[i]==null)

            return i;

    } else {

        for (int i = 0; i < size; i++)

        if (o.equals(elementData[i]))

            return i;

    }

    return -1;

}



/* 

* 从最后判断该元素是否存在,最先出现的地方的index

*/

public int lastIndexOf(Object o) {

    if (o == null) {

        for (int i = size-1; i >= 0; i--)

            if (elementData[i]==null)

            return i;

    } else {

        for (int i = size-1; i >= 0; i--)

            if (o.equals(elementData[i]))

                return i;

    }

    return -1;

}



/* 

* 加集合转换成数组,

*/

public Object[] toArray() {

    return Arrays.copyOf(elementData, size);

}



/* 

* 将集合转入到a中,a是对象,不能是基础数据类型

*看到实现原理了,宝宝建议不要拿有值的a 怎么搞,会出事的

*/

@SuppressWarnings("unchecked")

public <T> T[] toArray(T[] a) {

    if (a.length < size) //当a的长度小于集合是,返回本集合的数组

        // Make a new array of a's runtime type, but my contents:

        return (T[]) Arrays.copyOf(elementData, size, a.getClass());



    System.arraycopy(elementData, 0, a, 0, size); //将集合全部转入a中从0开始

    if (a.length > size)

        a[size] = null;



    return a;

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值