zoukankan      html  css  js  c++  java
  • 源码分析笔记Vector

    概述

    继承抽象类AbStractList,实现接口List、RandomAccess、Cloneable以及序列化接口
    默认容量大小为10,扩容增量为0,扩容为原容量的2倍
    如设置的增量大于0,则扩容为(原容量+增量)
    支持随机访问,添加删除元素较慢
    线程安全的动态数组,方法加上了synchronized同步锁,故性能较低
    源码

    字段信息

    public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
    /**
    * 保存数据的数组
    */
    protected Object[] elementData;

    /**
    * 元素个数
    */
    protected int elementCount;

    /**
    * 容量增量,可以指定扩容时,容量扩大多少
    */
    protected int capacityIncrement;

    /** 序列化ID */
    private static final long serialVersionUID = -2767605614048989439L;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    构造方法

    /**
    *主要的构造方法,内部也是调用该方法
    *initialCapacity 初始容量
    *capacityIncrement 增量,每次扩容时增加的容量大小
    */
    public Vector(int initialCapacity, int capacityIncrement) {
    super();
    //判断初始容量的合法性
    if (initialCapacity < 0)
    throw new IllegalArgumentException("Illegal Capacity: "+
    initialCapacity);
    //创建initialCapacity大小的Object数组
    this.elementData = new Object[initialCapacity];
    //指定增量大小
    this.capacityIncrement = capacityIncrement;
    }

    /**
    *指定初始容量,但不指定增量
    *也就是增量为0
    */
    public Vector(int initialCapacity) {
    //调用2个参数的构造方法
    this(initialCapacity, 0);
    }

    /**
    *无参构造方法,默认初始容量为10,增量为0
    */
    public Vector() {
    this(10);
    }
    /**
    *传入另一集合,增量为传入集合的长度
    */
    public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    if (elementData.getClass() != Object[].class)
    elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    添加元素

    /**
    *添加元素
    */
    public synchronized boolean add(E e) {
    //数组修改次数记录
    modCount++;
    //容量检查,判断是否需要扩容
    ensureCapacityHelper(elementCount + 1);
    //添加元素
    elementData[elementCount++] = e;
    return true;
    }

    /**
    *在指定位置添加元素
    */
    public void add(int index, E element) {
    insertElementAt(element, index);
    }

    public synchronized void insertElementAt(E obj, int index) {
    modCount++;
    //下标合法性检查,index不能大于元素个数
    if (index > elementCount) {
    throw new ArrayIndexOutOfBoundsException(index
    + " > " + elementCount);
    }
    //容量检查
    ensureCapacityHelper(elementCount + 1);
    //数组拷贝
    //将index开始,长度为elementCount-index的数组,往后移动一位
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    elementData[index] = obj;
    elementCount++;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    扩容操作

    /**
    *容量检查,判断是否需要扩容
    */
    private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
    grow(minCapacity);
    }

    /**
    *最大容量门限,最大容量为Integer.MAX_VALUE
    */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    /**
    *实际的扩容方法
    */
    private void grow(int minCapacity) {
    // 当前容量
    int oldCapacity = elementData.length;
    //计算新的容量
    //如果没有传入增量大小,则扩容为当前容量的2倍(2*oldCapacity)
    //如果有设置增量大小,如果增量小于0,则扩容2倍;如果大于0,则扩容为(oldCapacity+增量大小)
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
    capacityIncrement : oldCapacity);
    //判断新的容量的大小是否满足最小容量需要,如不满足,则直接扩容为所需要的容量大小
    if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
    //判断是否达到最大容量门限
    if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);
    //数组扩容,该方法代价较大,将数组扩容为newCapacity大小
    elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
    //判断所需的最小容量是否整数溢出
    if (minCapacity < 0) // overflow
    throw new OutOfMemoryError();
    //扩容的最大容量大小为Integer.MAX_VALUE
    return (minCapacity > MAX_ARRAY_SIZE) ?
    Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    小结

    默认扩容大小为原容量的2倍;设置了大于0的增量,扩容大小则为原容量+增量
    最大容量为Integer.MAX_VALUE,门限为Integer.MAX_VALUE-8
    添加元素顺序:传入所需的容量大小 -> 判断是否需要扩容 -> 执行扩容操作(计算新的容量大小、调用Arrays.copyOf(object[], newCapacity)) -> 添加元素
    因Arrays.copyOf()代价较大,故在创建Vector时应尽量设置集合大小
    删除元素

    /**
    *根据指定下标删除元素,返回删除元素的值
    */
    public synchronized E remove(int index) {
    modCount++;
    if (index >= elementCount)
    throw new ArrayIndexOutOfBoundsException(index);
    //获取保存index下标的元素值
    E oldValue = elementData(index);
    //计算拷贝移动的数组长度
    int numMoved = elementCount - index - 1;
    //长度大于0,则将index下标后面的元素往前拷贝移动一个位置
    if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
    numMoved);
    //将新空出来的下标位置填充为null,让gc可以回收内存
    elementData[--elementCount] = null; // Let gc do its work

    return oldValue;
    }
    /**
    *删除特定元素值,因为不确定集合中是否存在该元素,故返回boolean值,返回是否删除成功
    */
    public boolean remove(Object o) {
    return removeElement(o);
    }

    public synchronized boolean removeElement(Object obj) {
    modCount++;
    //获取指定元素值第一次出现的下标,没有找到则返回-1
    int i = indexOf(obj);
    if (i >= 0) {
    //根据指定下标删除元素
    removeElementAt(i);
    return true;
    }
    //没有找到指定元素,返回false,删除失败
    return false;
    }

    /**
    *根据下标删除元素,无返回值
    */
    public synchronized void removeElementAt(int index) {
    modCount++;
    //判断下标是否合法
    if (index >= elementCount) {
    throw new ArrayIndexOutOfBoundsException(index + " >= " +
    elementCount);
    }
    else if (index < 0) {
    throw new ArrayIndexOutOfBoundsException(index);
    }
    //同remove(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 */
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    小结

    remove(int index) 与 removeElementAt(int index)区别为remove方法返回删除元素的值,而removeElementAt无返回值
    根据元素内容删除不一定删除成功,可能集合中无目标元素
    手动缩容

    /**
    *手动缩小内部数组容量
    */
    public synchronized void trimToSize(http://www.amjmh.com) {
    modCount++;
    int oldCapacity = elementData.length;
    //判断数组中元素个数与数组长度大小
    if (elementCount < oldCapacity) {
    elementData = Arrays.copyOf(elementData, elementCount);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    手动扩容

    /**
    *传入一个容量大小,大于当前集合容量,将扩容
    */
    public synchronized void ensureCapacity(int minCapacity) {
    if (minCapacity > 0) {
    modCount++;
    //判断minCapacity是否大于数组容量,是否执行扩容操作
    ensureCapacityHelper(minCapacity);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    设置集合大小

    /**
    *设置容量大小
    *如果大于当前数组容量,则扩容
    *如果小于当前数组容量,则将操出的部分填充为null,让gc可以回收该部分内存
    */
    public synchronized void setSize(int newSize) {
    modCount++;
    if (newSize > elementCount) {
    ensureCapacityHelper(newSize);
    } else {
    for (int i = newSize ; i < elementCount ; i++) {
    elementData[i] = null;
    }
    }
    elementCount = newSize;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    与ArrayList比较

    Vector是线程安全的,在方法上加了synchronize同步锁,故访问速度比ArrayList慢,性能较低;最好使用ArrayList,因为同步操作完全可以有我们自己来控制
    ArrayList扩容是1.5倍(oldCapacity >> 1),Vector默认是2倍
    总结

    使用时最好指定容量大小
    删除元素时不会自己缩容
    ---------------------

  • 相关阅读:
    使用jmeter进行接口测试
    jenkins默认插件
    【机器学习】关于PCA 昕
    雲瑞文件直链分享软件
    FOB离岸价
    【数据分享】某地区1959~2019年60年降雨量时间序列数据
    【数据分享】银行客户流失Bank Customer Churn数据
    【数据分享】糖尿病患者研究数据集
    【数据分享】维基百科Wiki负面有害评论(网络暴力)文本数据多标签分类挖掘可视化
    C# Speech
  • 原文地址:https://www.cnblogs.com/ly570/p/11257591.html
Copyright © 2011-2022 走看看