源码解析ArrayList和Vector

源码解析ArrayList和Vector

ArrayList类的定义

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
...
}

ArrayList继承了AbstractList,实现了List、RandomAccess、Cloneable、Serializable接口。

实现了List接口,可以实现List的一些增、删、改、查等

实现了RandomAccess接口,表明可以被随机访问,可以通过下标来获取元素。

实现了Cloneable接口,表明可以被克隆

实现了Serializable表明可以被序列化

ArrayList的构造方法和属性

//默认的初始化容量
private static final int DEFAULT_CAPACITY = 10;
//默认的空数组,用来初始化空数组的时候使用
private static final Object[] EMPTY_ELEMENTDATA = {};
//默认构造函数里面的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//保存ArrayList数据的对象数组缓冲区
transient Object[] elementData; 
//集合的长度
private int size;
//带int参数的构造函数,如果传入的参数initialCapacity>0,则设置新建一个长度为initialCapacity的数组;
//如果等于0,则设置为空数组;小于0会抛出异常
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);
    }
}
//没有参数的构造方法,当第一次添加元素的时候扩容10
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//传入集合参数来初始化ArrayList
public ArrayList(Collection<? extends E> c) {
    Object[] a = c.toArray();    //将集合转化成对象数组
    if ((size = a.length) != 0) {
        if (c.getClass() == ArrayList.class) {
            elementData = a;  //然后赋值给elementData
        } else {
        	//如果c.toArray()出错,利用Arrays.copyOf来复制集合中的元素,然后给elementData
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        // 如果集合中没有元素,则将EMPTY_ELEMENTDATA空数组赋值给elementData
        elementData = EMPTY_ELEMENTDATA;
    }
}

ArrayList的添加元素方法

add(E e)方法

public boolean add(E e) {
    modCount++;   //操作计数
    add(e, elementData, size); //调用添加函数
    return true;
}

private void add(E e, Object[] elementData, int s) {
    if (s == elementData.length)   //判断elementData数组的长度和元素个数
        elementData = grow();     //如果相等就扩容
    elementData[s] = e;     //在数组末尾添加元素
    size = s + 1;          //修改size的值
}

private Object[] grow() {
    return grow(size + 1);
}


private Object[] grow(int minCapacity) {
    int oldCapacity = elementData.length;
    if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        int newCapacity = ArraysSupport.newLength(oldCapacity,
                minCapacity - oldCapacity, /* minimum growth */
                oldCapacity >> 1           /* preferred growth */);//默认扩容一半
        return elementData = Arrays.copyOf(elementData, newCapacity);//构建扩容后的数组
    } else {
        return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
    }
}

add(int index, E element)通过索引添加

public void add(int index, E element) {
    rangeCheckForAdd(index);//判断是否越界,越界抛出异常
    modCount++;
    final int s;
    Object[] elementData;
    if ((s = size) == (elementData = this.elementData).length)//判定是否需要扩容
        elementData = grow(); 
    System.arraycopy(elementData, index,
                     elementData, index + 1,
                     s - index); //将index后面的数据向后移一位
    elementData[index] = element;  //将index索引位赋值
    size = s + 1;
}

addAll(Collection<? extends E> c)

public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();//将集合转化为数组对象
    modCount++;
    int numNew = a.length;
    if (numNew == 0)
        return false;
    Object[] elementData;
    final int s;
    if (numNew > (elementData = this.elementData).length - (s = size))//判定是否扩容
        elementData = grow(s + numNew);
    System.arraycopy(a, 0, elementData, s, numNew);//复制数组完成批量赋值
    size = s + numNew;
    return true;
}

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

public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);//判定是否越界,越界抛出异常

    Object[] a = c.toArray();//将集合转化为数组对象
    modCount++;
    int numNew = a.length;
    if (numNew == 0)
        return false;
    Object[] elementData;
    final int s;
    if (numNew > (elementData = this.elementData).length - (s = size))//判定是否扩容
        elementData = grow(s + numNew);

    int numMoved = s - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index,
                         elementData, index + numNew,
                         numMoved);//如果numMoved>0,将index后面的数据向后移动numNew步
    System.arraycopy(a, 0, elementData, index, numNew);
    size = s + numNew;
    return true;
}

ArrayList的增加操作在添加之前,都会想判定是否扩容,如果扩容就会大量的复制数组,所以用System.arraycopy提高效率。

ArrayList删除元素方法

remove(int index)通过索引删除

public E remove(int index) {
    Objects.checkIndex(index, size);
    final Object[] es = elementData;

    @SuppressWarnings("unchecked") E oldValue = (E) es[index];
    fastRemove(es, index);

    return oldValue;
}
private void fastRemove(Object[] es, int i) {
    modCount++;
    final int newSize;
    //判定删除一个元素后,是否大于索引值i
    if ((newSize = size - 1) > i)
    	//把i索引值后面的元素向前移一步
        System.arraycopy(es, i + 1, es, i, newSize - i);
    //避免内存泄漏
    es[size = newSize] = null;
}

remove(Object o)按照对象删除

public boolean remove(Object o) {
    final Object[] es = elementData;
    final int size = this.size;
    int i = 0;//首次出现元素的位置记录
    //寻找要删除元素
    found: {
        if (o == null) {
            for (; i < size; i++)
                if (es[i] == null)
                    break found;
        } else {
            for (; i < size; i++)
                if (o.equals(es[i]))
                    break found;
        }
        //如果没找到就返回false
        return false;
    }
    //找到后就按照索引删除
    fastRemove(es, i);
    return true;
}

ArrayList更改元素的值

set(int index, E element)

public E set(int index, E element) {
    Objects.checkIndex(index, size);//越界检查
    E oldValue = elementData(index);//拿出元素
    elementData[index] = element;//覆盖元素
    return oldValue;//返回元素
}

ArrayList查看元素的值

get(int index)

public E get(int index) {
    Objects.checkIndex(index, size);//越界检查
    return elementData(index);//通过下标取出数据
}

E elementData(int index) {
    return (E) elementData[index];
}

ArrayList小结:

  • ArrayList的底层是数组实现的,长度是动态的增加
  • 扩容的长度是原来的长度的一半
  • 实现了RandomAccess接口,使得读取数据很容易
  • 添加和删除操作会大量的复制数组,性能较差
  • ArrayList的方法没有synchronized修饰或者加锁,所以线程是不安全的

ArrayList和Vector的区别

区别主要有两个:

  • 扩容的数量不一样
  • Vector的线程有synchronized修饰,所以线程是安全的

首先看下Vector扩容的源码

private Object[] grow() {
    return grow(elementCount + 1);
}

private Object[] grow(int minCapacity) {
    int oldCapacity = elementData.length;
    int newCapacity = ArraysSupport.newLength(oldCapacity,
            minCapacity - oldCapacity, /* minimum growth */
            //如果容量增量capacityIncrement大于0,则扩容增加capacityIncrement;如果小于或者等于0,则翻倍原来的长度
            capacityIncrement > 0 ? capacityIncrement : oldCapacity 
                                       /* preferred growth */);
    return elementData = Arrays.copyOf(elementData, newCapacity);
}

看一下一些基本的函数源码

//添加
public synchronized boolean add(E e) {
    modCount++;
    add(e, elementData, elementCount);
    return true;
}
//删除
public synchronized E remove(int index) {
    modCount++;
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    E oldValue = elementData(index);

    int numMoved = elementCount - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--elementCount] = null; // Let gc do its work

    return oldValue;
}
//修改
public synchronized E set(int index, E element) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}
//查询
public synchronized E get(int index) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    return elementData(index);
}

可以看到这些基本的方法都是synchronized修饰的,所以是线程同步的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值