Android - 数据结构解析 Vector

239 阅读5分钟

描述

Vector是一个基于数组实现的集合容器类,几乎和ArrayList的实现思想相同,但是保证了线程操作的安全性。

构造器

Vector的构造方法总共有4个。

  1. 无参构造器
// 这个构造器会构造一个初始长度为10,增长容量为0的向量对象
public Vector() {
    // 直接调用预期长度的构造器,#2
    this(10);
}
  1. 预设初始容量的构造器
public Vector(int initialCapacity) {
    // 调用2个参数的构造器
    this(initialCapacity, 0);
}
  1. 预设初始容量和容量增长数量的构造器
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    // 对传入的预期容量做合规性检查
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    // 直接根据预期长度初始化保存数据的数组
    this.elementData = new Object[initialCapacity];
    // 初始化容量扩容增长的数值
    this.capacityIncrement = capacityIncrement;
}
  1. 从已有集合创建的构造器
public Vector(Collection<? extends E> c) {
    // 将传入的集合转化为数组,直接赋值给存储的数组
    elementData = c.toArray();
    // 记录初始化时的集合元素个数
    elementCount = elementData.length;
    // 健壮性代码
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

add

add方法有2个重载,这个是跟ArrayList一样的

  1. 在集合尾部添加新对象
// 注意,这个方法是用 synchronized 关键词修饰来保证线程安全的
public synchronized boolean add(E e) {
    modCount++;
    // 有需要的话进行扩容,预期的扩容容量最小值就是当前元素个数+1
    ensureCapacityHelper(elementCount + 1);
    // 将当前的集合计数+1
    // 在最后一个位置放入新元素对象
    elementData[elementCount++] = e;
    return true;
}
  1. 在指定索引的位置插入新元素
public void add(int index, E element) {
    insertElementAt(element, index);
}

public synchronized void insertElementAt(E obj, int index) {
    modCount++;
    // 保证插入的索引号没有超过当前已有元素的最大值
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index
                                                 + " > " + elementCount);
    }
    // 有必要的话先进行扩容,扩容的最小期望容量为当前集合长度+1
    ensureCapacityHelper(elementCount + 1);
    // 将当前数组中的元素从index位置开始,往后移动一位
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    // 将插入的新对象放置在index索引对应的位置
    elementData[index] = obj;
    // 更新当前集合的新容量
    elementCount++;
}

扩容

private void ensureCapacityHelper(int minCapacity) {
    // 只有当期望的新容量比当前数组已分配的容量大的时候,才进行真正的扩容
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

private void grow(int minCapacity) {
    // 获取扩容前的数组的容量
    int oldCapacity = elementData.length;
    // 如果设置了每次扩容的增长容量,也就是在构造器中传入的参数,那么就在原来容量的基础上新增capacityIncrement个数的新容量。
    // 如果没有设置,那么新容量就是老容量的2倍。
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    // 如果计算出的新容量比预期的容量还小,那么以传入的预期容量为准
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    // 如果超过了最大容量,那么就直接给新容量虚拟机能给的最大容量
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // 将原数组中的元素拷贝到新数组中并且赋值给数组对象
    elementData = Arrays.copyOf(elementData, newCapacity);
}

remove

remove方法同样有2个重载。

  1. 删除指定索引位置的元素
// 同样使用 synchronized 关键词保证线程安全
public synchronized E remove(int index) {
    modCount++;
    // 保证删除的索引号不会超过当前已有元素的最大值
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    // 获取到删除之前的元素
    E oldValue = elementData(index);

    // 计算删除元素以后需要移动的元素的个数,需要移动的元素个数为,
    // 从index开始到最后一个元素的所有元素的个数
    int numMoved = elementCount - index - 1;
    // 只有当有需要移动的元素才操作数组进行移动
    if (numMoved > 0)
        // 将从index+1开始的所有元素都移动到index位置
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    // 将集合长度减一
    // 将当前数组中的最后一个元素指向null,等待GC回收
    elementData[--elementCount] = null; // Let gc do its work
    // 返回被删除的元素
    return oldValue;
}
  1. 删除指定的对象
public boolean remove(Object o) {
    return removeElement(o);
}

public synchronized boolean removeElement(Object obj) {
    modCount++;
    // 先找到该对象是在数组中的哪个索引号对应的位置
    int i = indexOf(obj);
    // 如果索引号是一个合法的位置
    if (i >= 0) {
        // 删除这个索引号对应的元素
        removeElementAt(i);
        return true;
    }
    return false;
}

public int indexOf(Object o) {
    // 从数组的第一个元素开始搜索当前元素的索引号
    return indexOf(o, 0);
}

// 第二个参数代表要从哪一个索引号开始搜索
public synchronized int indexOf(Object o, int index) {
    if (o == null) {
        for (int i = index ; i < elementCount ; i++)
            if (elementData[i]==null)
                // 注意:这里返回的是第一个为Null的对象的索引号
                return i;
    } else {
        for (int i = index ; i < elementCount ; i++)
            if (o.equals(elementData[i]))
                // 注意:这里返回的是第一个和传入对象相等的对象的索引号
                return i;
    }
    return -1;
}

// 这个方法整体上和#1是相同的
public synchronized void removeElementAt(int index) {
    modCount++;
    if (index >= elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                 elementCount);
    }
    else if (index < 0) {
        throw new ArrayIndexOutOfBoundsException(index);
    }
    int j = elementCount - index - 1;
    if (j > 0) {
        System.arraycopy(elementData, index + 1, elementData, index, j);
    }
    elementCount--;
    elementData[elementCount] = null; /* to let gc do its work */
}

get

public synchronized E get(int index) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    return elementData(index);
}

// 直接从数组中找到对应索引号的对象,强制转化为目标类型之后返回
E elementData(int index) {
    return (E) elementData[index];
}

set

public synchronized E set(int index, E element) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    // 记录原来的值
    E oldValue = elementData(index);
    // 将新设置的对象赋值给当前index位置
    elementData[index] = element;
    // 返回原来的元素对象
    return oldValue;
}

清空

public void clear() {
    removeAllElements();
}

public synchronized void removeAllElements() {
    modCount++;
    // 循环的将数组中的所有元素都指向null,让虚拟机在下一次GC的时候将这些空间收回
    for (int i = 0; i < elementCount; i++)
        elementData[i] = null;
    // 将集合长度设置为0
    elementCount = 0;
}

其他

ArrayList比起来,绝大多数的操作和实现都是类似的,最大的区别有2个。

  1. Vector通过在主要的操作方法上使用synchronized关键词,来保证线程的安全性
  2. Vector在扩容的时候的策略跟ArrayList不同,ArrayList扩容的时候为扩大到原来的1.5倍,Vector直接扩大1倍