集合源码分析之--ArrayList

ArrayList类图结构

需要查看

Iterable顶层接口,点一下Iterable顶层接口分析

Collection接口分析,点一下Collection接口分析

AbstractCollection抽象类分析,点一下:AbstractCollection抽象类分析

AbstractList抽象类分析,点一下:AbstractList抽象类分析

类的结构
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
}
继承了AbstractList接口
实现了List接口、RandomAccess接口、Cloneable克隆接口、Serializable序列化接口

类的属性


//默认初始量
private static final int DEFAULT_CAPACITY = 10;
//定义一个空的数组
private static final Object[] EMPTY_ELEMENTDATA = {};
//transient加上的意思是将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会被序列化
//集合装载数据,使用数组进行装载
transient Object[] elementData;
//集合大小
private int size;

集合初始化

//提供带初始化容量的数组初始化
public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        //初始化数组
        this.elementData = new Object[initialCapacity];
}
//声明一个空集合
//与Vector集合的不同是,Vector初始化设置了一个为10的数组,而ArrayList直接设置为空数组
public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;//详见类属性(静态且不可变的一个空数组)
}
//将一个集合提供给ArrayList进行初始化:处理方式跟Vector集合一致
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
}

核心方法解析(主要包含底层集合数组扩容)

//将集合压缩(将集合中没有存储元素的部分删除)这个是改变底层存储集合数组的数组大小
public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = Arrays.copyOf(elementData, size);
        }
}
//确保数组容量够不够minCapacity最少需要的容量大小
public void ensureCapacity(int minCapacity) {
        //如果数组为空,最小最快默认为0,是否就使用默认增长量10
        int minExpand = (elementData != EMPTY_ELEMENTDATA)
            // any size if real element table
            ? 0
            // larger than default for empty table. It's already supposed to be
            // at default size.
            : DEFAULT_CAPACITY;
        //
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
}
//确保容量,
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);
}
//数组扩容minCapacity最小容量
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;//数组长度
        //新的容量=原数组长度+原数组长度/2
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        //如果新容量大于最小容量时,取最小容量;否则取新容量,然后还要根据
//新容量是否超过Int最大值以及Int-8(int-8再说一次防止内存溢出,因为JVM底层在数组头部加了一些默认的数据
        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-8,如果超过这个值时直接返回Int的最大值
private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
}

核心方法解析

//给定元素在素组的位置(从0开始)
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;
}

//给定元素在数组的位置(从后往前找size开始找)
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;
}
//转数据,思路就是使用底层native进行数组拷贝   
public Object[] toArray() {
    //拷贝数组elementData,拷贝长度为当前数组的元素个数
    return Arrays.copyOf(elementData, size);
}
//转数据,思路就是使用底层native进行数组拷贝
public Object[] toArray() {
    //拷贝数组elementData,拷贝长度为当前数组的元素个数
    return Arrays.copyOf(elementData, size);//这个拷贝是基于JVM的,速度相当快,Duang的一下就过去了
}
//告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
@SuppressWarnings("unchecked")
//默认default只能在 同一包内可见,所以外面访问不到也无法访问
default E elementData(int index) {
    //通过索引获取数组中元素
    return (E) elementData[index];
}
//根据给定索引,获取数组中元素    
public E get(int index) {
    //rangeCheck:注释部分为rangeCheck内部实现,判断是否是否越界
//  if (index >= size)
//        //outOfBoundsMsg:return "Index: "+index+", Size: "+size;    
//        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    rangeCheck(index);
    //获取元素
    return elementData(index);
}
//设置某个元素在给定索引位置
public E set(int index, E element) {
    rangeCheck(index);//判断给定索引是否超过元素个数
    //获取旧元素
    E oldValue = elementData(index);
    //给旧元素位置设置新元素
    elementData[index] = element;
    return oldValue;//返回旧元素
}
//添加某个元素到数组
public boolean add(E e) {
    //这里面已经完成了modCount++;
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    /**
     * --size++
     * 先执行+1后使用
     * 2个步骤
     * 1、将数组的元素个数+1;
     * 2、给size+1的位置设置新元素
     */
    elementData[size++] = e;
    return true;
}
//在数组某个位置添加元素
//1、首先要判断当前添加的位置是否超过数组大小(越界问题)以及添加的index必须的大于0吧
//2、数据要不要扩容
//3、数据拷贝【将加入的元素放到数组中】
//--先把要加入数组的元素位置空出来,通过拷贝移动的方式
//--System.arraycopy(数组,开始拷贝的位置,要拷贝的数据到,拷贝到哪里(开始拷贝的位置 + 1),拷贝长度(size - index));
//--这个意思就是把数组往后面移一个位置
//4、然后将空出来的位置把要加入的元素给填进去elementData[index] = 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++;//最后将数组大小+1
}
//给定索引的位置的数组元素要移除
//如果我自己做思路怎么搞?
//1、首先的判断移除的原生位置,是不是索引越界(大于0小于size)
//2、modCount要加1
//3、把要移除的位置元素取出来放起,用于返回用
//4、把数据要删除的位置给通过数组拷贝的方式释放出来;数组要减容
//5、System.arraycopy(数组,开始拷贝的位置(index+1),要拷贝的数据到,拷贝到哪里(index),拷贝长度(size - index - 1));
//6、然后将数组最后一个位置设置为null(主要是让GC回收)
//7、size--
public E remove(int index) {
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);
    //这里这样做的目的就是为了防止:要移除的位置就是在size位置
    int numMoved = size - index - 1;//-1的目的就是数组索引为0开始算;size为个数1开始算;
    //如果移除的元素不在数组末尾时,需要将数组往前移
    if (numMoved > 0)
        //要拷贝的数组、源数组要复制的起始位置(因为要删除,所以从Index+1开始拷贝)、拷贝到的数组、目的数组放置的起始位置、复制的长度
        System.arraycopy(elementData,index+1,elementData,index,numMoved);
    elementData[--size] = null; // clear to let GC do its work
    return oldValue;
}

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;
}

//fastRemove跟remove(int index)功能一样,只是少了越界判断    
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
}

//清空数组
public void clear() {
    modCount++;
    // clear to let GC do its work
    //将数组元素设置为null,GC回收
    for (int i = 0; i < size; i++)
        elementData[i] = null;
    size = 0;
}

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    //判断扩容及modCount++
    ensureCapacityInternal(size + numNew);  // Increments modCount
    //将新数组拷贝数组中
    System.arraycopy(a, 0, elementData, size, numNew);
    size += numNew;//将size设置为size+numNew
    return numNew != 0;
}




ArrayList迭代器

//
public Iterator<E> iterator() {
        return new Itr();
}
//这个跟Vector集合功能一致
private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            
            //这句话没有是吗用;Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            //elementData和这个ArrayList内提供了此方法
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
}

总观:

Vector和ArrayList其实底层实现都是一样的,只是Vector集合在动集合数组的时候方法上面加了synchronized已保证接口安全;而ArrayList为线程不安全的集合,但是效率上ArrayList》Vector接口的;

List总结:

可以重复,通过索引取出加入数据,顺序与插入顺序一致,可以含有null元素

ArrayList:底层数据结构使数组结构array,查询速度快,增删改慢,因为是一种类似数组的形式进行存储,因此它的随机访问速度极快;

Vector:底层是数组结构array,与ArrayList相同,查询速度快,增删改慢;

LinkedList:底层使用链表结构,增删速度快,查询稍慢;

ArrayList与Vector的区别:

1.如果集合中的元素数量大于当前集合数组的长度时,Vector的增长率是目前数组长度的100%,而ArryaList增长率为目前数组长度的50%。所以,如果集合中使用数据量比较大的数据,用Vector有一定优势

2.线程同步ArrayList是线程不同步,所以Vector线程安全,但是因为每个方法都加上了synchronized,所以在效率上小于ArrayList

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值