Vector源码学习

一.arraylist和vector异同

1.相同点

  • 都实现List接口(List用于存放多个元素,能够维护元素的次序,并且允许元素的重复)
  • 底层都通过数组实现
  • 查找操作时,vector和arraylist使用的时间是相同的,都是0(1)
  • 都实现了RandomAccess接口

2.不同点

  • Vector支持线程的同步,因此它访问比Arraylist慢

  • Vector的扩容增长为2倍,ArrayList为1.5倍

二.源码部分

1.基本属性

//AbstractList 是一个抽象类,实现了List 接口
//RandomAccess接口是一个标记接口,用以标记实现的List集合具备快速随机访问的能力,随机访问就是随机的访问List中的任何一个元素。即可以通过元素的序号快速获取元素对象;这就是快速随机访问。
//Cloneable是标记型的接口,它们内部都没有方法和属性,实现 Cloneable来表示该对象能被克隆
//一个类实现Serializable接口,那么这个类就可以序列化了
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    protected Object[] elementData;
    //动态数组的实际大小
    protected int elementCount;
    //capacityIncrement 是动态数组的增长系数。如果在创建Vector时,指定了capacityIncrement的大小;则,每次当Vector中动态数组容量增加时>,增加的大小都是capacityIncrement。
    protected int capacityIncrement;
    //序列号
    private static final long serialVersionUID = -2767605614048989439L;
    private static final int MAX_ARRAY_SIZE = 2147483639;

3.构造函数

    /**
     * 构造函数
     * 1.指定容量大小和增长系数的vector
     * 2.指定容量的vector
     * 3.无参构造,初始容量大小为10
     * 4.指定集合的Vector构造函数
     * @param initialCapacity
     * @param capacityIncrement
     */
    //Vector(int size,int incr)
    public Vector(int initialCapacity, int capacityIncrement) {
        //初始容量数值越界判断,若小于0,则抛出异常
        if (initialCapacity < 0) {
            throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
        } else {
            //创建容量为initialCapacity大小的object数组
            this.elementData = new Object[initialCapacity];
            //增长系数赋值
            this.capacityIncrement = capacityIncrement;
        }
    }
    //Vector(int size)
    public Vector(int initialCapacity) {
        //capacityIncrement = 0
        this(initialCapacity, 0);
    }
    //Vector()
    public Vector() {
        //initialCapacity = 10 ,capacityIncrement = 0;
        this(10);
    }
    //Vector(Collection c)
    public Vector(Collection<? extends E> c) {
        //.toArray()用于将所有列表元素复制到新数组,或者可以说它用于将列表转换为数组。
        Object[] a = c.toArray();
        //数组实际长度被赋值
        this.elementCount = a.length;
        //判断c是否为arraylist类型
        if (c.getClass() == ArrayList.class) {
            this.elementData = a;
        } else {
            //Arrays.copyOf ()是创建一个新的数组(也就是分配了一个新的内存空间),然后调用System. arraycopy ()复制内容,赋值给新数组,然后返回新数组。
            //Object[].class为新的类型
            this.elementData = Arrays.copyOf(a, this.elementCount, Object[].class);
        }

    }
  • Array.copyOf()

3..扩容机制

    /**
     * vector扩容机制
     * @param minCapacity
     * @return
     */
    private Object[] grow(int minCapacity) {
        //返回object类型新容量的数组,用Arrays.copyOf来产生新容量大小的数组
        //newCapacity(minCapacity)去实际判断扩容后的新容量
        return this.elementData = Arrays.copyOf(this.elementData, this.newCapacity(minCapacity));
    }
//
    private Object[] grow() {
        return this.grow(this.elementCount + 1);
    }
//返回int值的新容量大小
    private int newCapacity(int minCapacity) {
        //旧的容量为当前数组的容量
        int oldCapacity = this.elementData.length;
        //一般情况下newCapacit为旧容量的2倍(),除了指定增长系数,其他情况下capacityIncrement的大小都为0
        int newCapacity = oldCapacity + (this.capacityIncrement > 0 ? this.capacityIncrement : oldCapacity);
        //和arraylist一样进行是否按增长系数进行增长的判断
        //不同的是,arraylist在数组容量很小的时候进行add操作就会进入下面方法体,或是用户手动ensureCapacity超过1.5倍增长的容量,也会进入
        //而vector为2倍增长,所以若用户手动设置的扩容量不会小于默认的扩容策略,可通过ensureCapacity和setsize进入
        if (newCapacity - minCapacity <= 0) {
            if (minCapacity < 0) {
                throw new OutOfMemoryError();
            } else {
                return minCapacity;
            }
        } else {
            //最大长度判断
            return newCapacity - 2147483639 <= 0 ? newCapacity : hugeCapacity(minCapacity);
        }
    }

    private static int hugeCapacity(int minCapacity) {
        //容量小于0,异常
        if (minCapacity < 0) {
            throw new OutOfMemoryError();
        } else {
            //超出最大值,返回最大值,否则返回minCapacity
            return minCapacity > 2147483639 ? 2147483647 : 2147483639;
        }
    }
//ensureCapacity() 方法用于设置具有指定容量大小的动态数组。
    public synchronized void ensureCapacity(int minCapacity) {
        //判断minCapacity是否合法
        if (minCapacity > 0) {
            //记录着集合的修改次数
            ++this.modCount;
            //minCapacity 大于数组长度,扩容
            if (minCapacity > this.elementData.length) {
                this.grow(minCapacity);
            }
        }

    }

4.其他方法

1.v.copyInto(str)

//v.copyInto(str)
    //v中数据赋值给str
    public synchronized void copyInto(Object[] anArray) {
        //elementData:原数组
        //0 : 起始位置
        // anArry: 目标数组
        //elementCount: 长度
        System.arraycopy(this.elementData, 0, anArray, 0, this.elementCount);
    }

2.setSize(int newSize)

    public synchronized void setSize(int newSize) {
        //记录着集合的修改次数
        ++this.modCount;
        //如果新的大小大于数组目前的容量,带着newSize作为参数扩容
        if (newSize > this.elementData.length) {
            this.grow(newSize);
        }

        Object[] es = this.elementData;
        int to = this.elementCount;
//如果用户设置的newSize小于elementCount时,则把超长的部分数据设置为null
        for(int i = newSize; i < to; ++i) {
            es[i] = null;
        }
//将数组的实际长度,有效值改为用户设置的size
        this.elementCount = newSize;
    }

3.Add方法

  • add(E e)add(int index, E element)方法和ArrayList基本相同,只是加了synchronized是同步的

  • addAll(Collection<? extends E> c)

    //将指定 Collection 中的所有元素添加到此向量的末尾,按照指定 collection 的迭代器所返回的顺序添加这些元素。
        public boolean addAll(Collection<? extends E> c) {
            //将collection转化为数组
            Object[] a = c.toArray();
            //增加集合修改次数
            ++this.modCount;
            //记录当前数组a的长度
            int numNew = a.length;
            //如果长度为0,则返回false
            if (numNew == 0) {
                return false;
            } else {
                //当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块
                //整个迭代的过程中如果在循环外面不加同步代码,在一次次迭代之间,其他线程对于这个容器的add或者remove会影响整个迭代的预期效果,所以这里需要用户在整个循环外面加上synchronized(list)
                synchronized(this) {
                    Object[] elementData = this.elementData;
                    int s = this.elementCount;
                    //要加进来的数组a长度大于原对象所剩下的容量则扩容
                    if (numNew > elementData.length - s) {
                        elementData = this.grow(s + numNew);
                    }
                    //从vector最后一个元素后开始插入数组a
                    System.arraycopy(a, 0, elementData, s, numNew);
                    //动态数组有效值加numNew
                    this.elementCount = s + numNew;
                    //addAll成功
                    return true;
                }
            }
        }
    

4.remove方法

4.1 boolean remove(Object o)
//移除此向量中指定元素的第一个匹配项,如果向量不包含该元素,则元素保持不变。
    public boolean remove(Object o) {
        //成功返回true,失败返回false
        return this.removeElement(o);
    }
4.2 Object remove(int index)
//移除此向量中指定位置的元素
    public synchronized E remove(int index) {
        //增加修改次数
        ++this.modCount;
        //如果索引值>=实际大小值,抛出异常
        if (index >= this.elementCount) {
            throw new ArrayIndexOutOfBoundsException(index);
        } else {
            //记录删除的值
            E oldValue = this.elementData(index);
            //记录要移动的次数(索引值后一位到最后)
            int numMoved = this.elementCount - index - 1;
            //索引值不是最后一位
            if (numMoved > 0) {
                //从index位置开始,将index+1开始的值到(index-index+numMoved)的值覆盖上
                System.arraycopy(this.elementData, index + 1, this.elementData, index, numMoved);
            }
            //实际大小的最后一位赋值为null
            this.elementData[--this.elementCount] = null;
            //返回删除的值
            return oldValue;
        }
    }
4.3 boolean removeElement(Object obj)
//从此向量中移除变量的第一个(索引最小的)匹配项。
    public synchronized boolean removeElement(Object obj) {
        //增加集合修改次数
        ++this.modCount;
        //返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1
        int i = this.indexOf(obj);
        //存在这个obj
        if (i >= 0) {
            //直接删除
            this.removeElementAt(i);
            return true;
        } else {
            //没有这个obj,返回false
            return false;
        }
    }
4.4 void removeElementAt(int index)
//void removeElementAt(int index),删除指定索引处的组件
    public synchronized void removeElementAt(int index) {
        //如果index超出范围则抛出异常ArrayIndexOutOfBoundsException
        if (index >= this.elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + this.elementCount);
        } else if (index < 0) {
            //index < 0, 则抛出ArrayIndexOutOfBoundsException
            throw new ArrayIndexOutOfBoundsException(index);
        } else {
            //index正常范围
            //和remove(int index)方法numMove一样,j为移动次数
            int j = this.elementCount - index - 1;
            //index不指向最后一位
            if (j > 0) {
                //则开始逐个覆盖
                System.arraycopy(this.elementData, index + 1, this.elementData, index, j);
            }
            //数组修改次数加一
            ++this.modCount;
            //动态数组实际有效值 - 1
            --this.elementCount;
            //删除前的最后一位,因为已经移到前一位,或是被删除了,所以赋值为空
            this.elementData[this.elementCount] = null;
        }
    }
4.5 protected void removeRange(int fromIndex, int toIndex)
//从此 List 中移除其索引位于 fromIndex(包括)与 toIndex(不包括)之间的所有元素。
    protected synchronized void removeRange(int fromIndex, int toIndex) {
        //增加集合修改次数
        ++this.modCount;
        this.shiftTailOverGap(this.elementData, fromIndex, toIndex);
    }

//void removeRange(int fromIndex, int toIndex)调用
    private void shiftTailOverGap(Object[] es, int lo, int hi) {
        //由es, hi可看出删除范围不包括toIndex,
        System.arraycopy(es, hi, es, lo, this.elementCount - hi);
        //to为删除前数组长度
        int to = this.elementCount;
        //将删除的地方赋值null
        for(int i = this.elementCount -= hi - lo; i < to; ++i) {
            es[i] = null;
        }

    }
posted @ 2022-02-19 13:37  ftfty  阅读(23)  评论(0编辑  收藏  举报