zoukankan      html  css  js  c++  java
  • Java数据结构漫谈-Vector

    List除了ArrayList和LinkedList之外,还有一个最常用的就是Vector。

    Vector在中文的翻译是矢量,向量,所以大家喜欢把Vector叫做矢量数组,或者向量数组。

    其实就底层实现来说Vector与ArrayList的实现大同小异,都是使用数组作为底层的存储器,在上面进行了一些列的操作封装,而且都实现了List的数据接口。

    最主要的区别就是Vector的大部分操作增加了线程同步的功能,这也是Vector与其他List最大不同的地方,Vector是线程安全的。

        protected Object[] elementData; //数组作为底层存储器
    
        protected int elementCount; //记录了当前有多少个元素了
    
        protected int capacityIncrement; //每次扩展的时候需要扩展的数量
    
        public Vector(int initialCapacity, int capacityIncrement) {
            super();
            if (initialCapacity < 0)
                throw new IllegalArgumentException("Illegal Capacity: "+
                                                   initialCapacity);
            this.elementData = new Object[initialCapacity];
            this.capacityIncrement = capacityIncrement;
        }
    
        public Vector(int initialCapacity) {
            this(initialCapacity, 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);
        }

     这里面提供了与ArrayList相同的各种操作,下面简单说明一下:

    1.复制内容到指定的数组,如果数组不够大,则抛出越界错误。

        public synchronized void copyInto(Object[] anArray) {
            System.arraycopy(elementData, 0, anArray, 0, elementCount);
        }

    这里使用了System.arraycopy,后面还有很多地方使用了这个函数,其时间复杂度是o(n)。

    2.在使用Vector的过程中,会出现需要扩容的情况,扩容之后又删除元素,就会造成很多元素空间被浪费的情况,如果担心浪费空间,就可以调用下面的函数进行无用空间trim:

        public synchronized void trimToSize() {
            modCount++;
            int oldCapacity = elementData.length;
            if (elementCount < oldCapacity) {
                elementData = Arrays.copyOf(elementData, elementCount);
            }
        }

    可以看出这里就是开辟了一个正好需要的空间,把元素都拷贝到这个空间中,原来的数组空间会在vm空闲的时候进行回收。

    3.上面说到了在数组容量不够的时候,会进行扩容,这里列出了一系列的包括扩容和获取与判断数组大小的函数:

        public synchronized void ensureCapacity(int minCapacity) {//进行容量调整
            if (minCapacity > 0) {
                modCount++;
                ensureCapacityHelper(minCapacity);
            }
        }
    
        private void ensureCapacityHelper(int minCapacity) {//进行容量调整
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)//只有指定的容量大于元素个数的时候才进行容量调整
                grow(minCapacity);
        }
    
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
        private void grow(int minCapacity) {//扩容操作
            // overflow-conscious code
            int oldCapacity = elementData.length;//目前的容量
            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);//开辟一个新空间,拷贝数据到新空间,旧空间将被VM自动回收
        }
    
        private static int hugeCapacity(int minCapacity) {
            if (minCapacity < 0) // overflow
                throw new OutOfMemoryError();
            return (minCapacity > MAX_ARRAY_SIZE) ?//其实不明白只有8的差距,为什么这么纠结
                Integer.MAX_VALUE :
                MAX_ARRAY_SIZE;
        }
    
        public synchronized void setSize(int newSize) {//设置当前Vector的元素数量
            modCount++;
            if (newSize > elementCount) {//比当前的元素个数大,就扩容,还不一定需要扩,看ensureCapacityHelper就明白
                ensureCapacityHelper(newSize);
            } else {
                for (int i = newSize ; i < elementCount ; i++) {//如果比当前的元素个数少,就把多出来的元素都抹掉
                    elementData[i] = null;
                }
            }
            elementCount = newSize;//调整当前元素的个数
        }
    
        public synchronized int capacity() {
            return elementData.length;
        }
    
        public synchronized int size() {
            return elementCount;
        }
    
        public synchronized boolean isEmpty() {
            return elementCount == 0;
        }

    上面的就是整个的扩容和设置元素数量等的一些操作函数的解释。

    4.查找对象所在的index是List的一个重要的操作,其对应的主要的函数如下所示:

        public boolean contains(Object o) {//判断一个对象o是否在Vector中
            return indexOf(o, 0) >= 0;
        }
    
        public int indexOf(Object o) {//判断一个对象o在Vector中第一次出现的位置
            return indexOf(o, 0);
        }
    
        public synchronized int indexOf(Object o, int index) {//判断一个对象在Vector中的index之后第一次出现的位置
            if (o == null) {
                for (int i = index ; i < elementCount ; i++)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = index ; i < elementCount ; i++)//使用遍历对比的方式进行判断
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }
    
        public synchronized int lastIndexOf(Object o) {//判断在Vector中自后向前查找对象o的第一次出现的位置
            return lastIndexOf(o, elementCount-1);
        }
    
    
        public synchronized int lastIndexOf(Object o, int index) {
            if (index >= elementCount)
                throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
    
            if (o == null) {
                for (int i = index; i >= 0; i--)
                    if (elementData[i]==null)
                        return i;
            } else {
                for (int i = index; i >= 0; i--)//自后向前倒着遍历这个Vector查找
                    if (o.equals(elementData[i]))
                        return i;
            }
            return -1;
        }

    可以看出,只要涉及到确定Vector中对象o的位置,就需要遍历对比查找,而遍历对比查找的时间复杂度是o(n)

    5.根据index对Vector进行操作也有一系列的函数:

        public synchronized E elementAt(int index) {//根据index获取Vector中的元素
            if (index >= elementCount) {
                throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
            }
    
            return elementData(index);
        }
    
      
        public synchronized E firstElement() {//获取第一个元素
            if (elementCount == 0) {
                throw new NoSuchElementException();
            }
            return elementData(0);
        }
    
        public synchronized E lastElement() {//获取最后一个元素
            if (elementCount == 0) {
                throw new NoSuchElementException();
            }
            return elementData(elementCount - 1);
        }
    
        public synchronized void setElementAt(E obj, int index) {//设置位置为index的元素
            if (index >= elementCount) {
                throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                         elementCount);
            }
            elementData[index] = obj;//直接设置,时间复杂度是o(1)
        }
    
        public synchronized void removeElementAt(int index) {//删除位置为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) {//如果不是最后一个需要进行元素位移,这个时候的时间复杂度是o(n)
                System.arraycopy(elementData, index + 1, elementData, index, j);
            }
            elementCount--;
            elementData[elementCount] = null; /* to let gc do its work *///把最后的值为null
        }
    
        public synchronized void insertElementAt(E obj, int index) {//在位置中间插入一个元素,时间复杂度是o(n)
            modCount++;
            if (index > elementCount) {
                throw new ArrayIndexOutOfBoundsException(index
                                                         + " > " + elementCount);
            }
            ensureCapacityHelper(elementCount + 1);//先进行扩容
            System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);//让出位置,时间复杂度是o(n)
            elementData[index] = obj;//直接赋值
            elementCount++;//计数加一
        }
    
        public synchronized void addElement(E obj) {
            modCount++;
            ensureCapacityHelper(elementCount + 1);
            elementData[elementCount++] = obj;//在队尾加入一个,时间复杂度是o(1)
        }
    
        public synchronized boolean removeElement(Object obj) {//删除Vector中出现的第一个对象obj
            modCount++;
            int i = indexOf(obj);
            if (i >= 0) {
                removeElementAt(i);
                return true;
            }
            return false;
        }
    
        public synchronized void removeAllElements() {//删除所有的元素,遍历,时间复杂度是o(n)
            modCount++;
            // Let gc do its work
            for (int i = 0; i < elementCount; i++)
                elementData[i] = null;
    
            elementCount = 0;
        }
    
        public synchronized Object clone() {//拷贝一个对象,时间复杂度是o(n)
            try {
                @SuppressWarnings("unchecked")
                    Vector<E> v = (Vector<E>) super.clone();
                v.elementData = Arrays.copyOf(elementData, elementCount);
                v.modCount = 0;
                return v;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError(e);
            }
        }
    
        public synchronized Object[] toArray() {//转换成数组,时间复杂度是o(n)
            return Arrays.copyOf(elementData, elementCount);
        }
    
        @SuppressWarnings("unchecked")
        public synchronized <T> T[] toArray(T[] a) {//转换成数组,时间复杂度是o(n)
            if (a.length < elementCount)
                return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
    
            System.arraycopy(elementData, 0, a, 0, elementCount);
    
            if (a.length > elementCount)
                a[elementCount] = null;
    
            return a;
        }
    
        @SuppressWarnings("unchecked")
        E elementData(int index) {//获取index对应的对象,时间复杂度是o(1)
            return (E) elementData[index];
        }
    
        public synchronized E get(int index) {//获取index对应的对象,时间复杂度是o(1)
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            return elementData(index);
        }
    
        public synchronized E set(int index, E element) {//设置index对应的对象,时间复杂度是o(1)
            if (index >= elementCount)
                throw new ArrayIndexOutOfBoundsException(index);
    
            E oldValue = elementData(index);
            elementData[index] = element;
            return oldValue;
        }
    
        public synchronized boolean add(E e) //在最后添加一个对象,时间复杂度是o(1),但有可能触发扩容操作
            modCount++;
            ensureCapacityHelper(elementCount + 1);
            elementData[elementCount++] = e;
            return true;
        }
    
        public boolean remove(Object o) {//删除第一次出现的对象o,时间复杂度是o(n)
            return removeElement(o);
        }
    
        public void add(int index, E element) {//在inedx上添加一个元素,时间复杂度是o(n),因为会触发元素位移
            insertElementAt(element, index);
        }
    
        public synchronized E remove(int index) {//删除index上面的元素,时间复杂度是o(n),因为会触发元素位移
            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;
        }

    以上是进行获取,增加和删除操作的时间复杂度。

    再次强调,Vector在涉及到元素更改的函数之前都加了关键字synchronized,是线程安全的。

  • 相关阅读:
    预热buffer pool
    MySQL · 性能优化· InnoDB buffer pool flush策略漫谈
    事务并发控制
    LOAD DATA INFILE – performance case study
    隐式锁
    percona-xtrabackup安装
    mysql 表空间及索引的查看方法
    mysql用户权限
    mysql修改数据库名
    MySQL对innodb某一个表进行移动
  • 原文地址:https://www.cnblogs.com/yakovchang/p/java_vector.html
Copyright © 2011-2022 走看看