`
tianruirui
  • 浏览: 5527 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

源码阅读之Vector

阅读更多

源码阅读是基于JDK7,本篇主要涉及Vector常用方法源码分析。Java技术分享微信公众号:JavaQ,公众号最新文章第一时间同步更新!欢迎围观!

1.概述
Vector实现了一个增长型的Object数组,可以包含任何类型的元素,包括null。像数组一样,它的元素可以使用下标索引值进行访问。为了容纳添加或删除后的元素,Vector的容量可以增长或收缩。每个Vector实例通过维护容量大小和容量增长因子来优化存储管理。Vector容量的大小要大于等于Vector中元素的实际个数,如果添加元素时需要扩容,则会按照增长因子的大小进行扩容。当需要添加大量的元素到Vector中,需要给它进行合适的扩容,这样可以减少增量式的内存再分配次数。像ArrayList一样,通过Vector的iterator方法和listIterator方法返回iterators时被设计成是fail-fast,当调用这两个方法的时候,如果Vector实例被从结构上进行了修改(指添加或删除一个或多个元素的操作,除了ListIterator的remove方法或add方法,或者显式调整底层数组的大小,仅仅设置元素的值不是结构上的修改),将会抛出ConcurrentModificationException,这样的设计避免了某个不确定的时间因为修改而出现的不可预知的问题。需要注意的是这个类的elements方法并不是fail-fast。Vector和ArrayList大体上的相同的,不同的是ArrayList是非同步的,而Vector是同步的,其实就是在实现的方法上使用synchronized进行同步。Vector具有同步的特性,是线程安全的,所以它的性能相对于ArrayList来说是低效的,因为同步操作需要消耗时间,针对于不需要使用线程安全的情况来说,推荐使用ArrayList代替Vector。Vector实现了RandomAccess接口可以进行快速的随机访问。Vector实现了Cloneable接口可进行clone操作。Vector实现了java.io.Serializable接口,可进行序列化操作。

2.数据结构
Vector类的声明代码如下,

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
由上面的代码段可以得出如下所示的类图,


Paste_Image.png
Vector中声明了如下一些属性,

protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;
protected transient int modCount = 0;
(1)elementData数组用于存储元素;
(2)elementCount为Vector中实际元素个数;
(3)capacityIncrement为Vector扩容的增长因子;
(4)modCount从AbstractList继承而来,用于记录从结构上修改此Vector的次数;

3.构造方法
提供了四个构造函数可供使用。

    //根据指定初始容量大小、容量增长因子构造一个空的Object数组
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    //根据指定初始容量大小、容量增长因子为零构造一个空的Object数组
    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    //初始容量大小为10、容量增长因子为0构造一个空的Object数组
    public Vector() {
        this(10);
    }

    //将Collection中的元素按照迭代次序存入elementData中
    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);
    }
4.扩容
当添加元素的时候,检查数组容量是否需要扩容。

    //使用synchronized进行同步
    public synchronized void ensureCapacity(int minCapacity) {
        if (minCapacity > 0) {
            modCount++;
            ensureCapacityHelper(minCapacity);
        }
    }

    //指定的扩容大小大于elementData数组的长度才进行扩容
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    //可分配的最大数组大小,因为一些VM需要在数组中预留字节头,所以需要减8
    //尝试去分配的数组大小超过了VM的限制会报OutOfMemoryError
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //从这里可以得出尝试扩容的大小可能是原容量加上增长因子的大小或原容量的二倍
    //扩容后最大容量大小是Integer.MAX_VALUE
    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);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
5.setSize方法

    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;
    }
设置容量大小为newSize。如果newSize大于当前的容量,则会进行扩容;否则,从newSize开始到末尾的所有元素会被丢弃,被设置为null。

6.capacity方法

    public synchronized int capacity() {
        return elementData.length;
    }
返回当前Vector的容量大小,是线程安全的。

7.size方法

    public synchronized int size() {
        return elementCount;
    }
返回当前Vector中元素的实际个数。

8.isEmpty方法

    public synchronized boolean isEmpty() {
        return elementCount == 0;
    }
判断当前Vector中元素的书籍个数是否等于零。

9.elements方法

    public Enumeration<E> elements() {
        return new Enumeration<E>() {
            int count = 0;

            public boolean hasMoreElements() {
                return count < elementCount;
            }

            public E nextElement() {
                synchronized (Vector.this) {
                    if (count < elementCount) {
                        return elementData(count++);
                    }
                }
                throw new NoSuchElementException("Vector Enumeration");
            }
        };
    }
返回一个Enumeration实例,用于遍历Vector。

10.contains方法

    public boolean contains(Object o) {
        return indexOf(o, 0) >= 0;
    }

    public synchronized int indexOf(Object o, int 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;
    }
从前向后遍历elementData数组,匹配第一个和o相等的元素,如果存在返回对应元素的下标序号,否则返回-1。这里需要注意的是o.equals(elementData[i]),这里是Objetc的equals方法,比较的是引用。

11.indexOf方法

    public int indexOf(Object o) {
        return indexOf(o, 0);
    }
从前向后查找匹配的第一个元素,若存在返回对应的索引下标,否则返回-1。

12.lastIndexOf方法

    public synchronized int lastIndexOf(Object 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--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
从后向前查找匹配的第一个元素,若存在返回对应的索引下标,否则返回-1。

13.elementAt方法

    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }
返回指定索引下标位置的元素。

14.firstElement方法

    public synchronized E firstElement() {
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(0);
    }
返回第一个元素。

15.lastElement方法

    public synchronized E lastElement() {
        if (elementCount == 0) {
            throw new NoSuchElementException();
        }
        return elementData(elementCount - 1);
    }
返回最后一个元素。

16.setElementAt方法

    public synchronized void setElementAt(E obj, int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        elementData[index] = obj;
    }
17.removeElementAt方法

    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;//GC回收
    }
18.insertElementAt方法

    public synchronized void insertElementAt(E obj, int index) {
        modCount++;
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
        //扩容判断及操作
        ensureCapacityHelper(elementCount + 1);
        //数据移动,其实是数组拷贝
        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
        elementData[index] = obj;
        elementCount++;
    }
19.addElement方法

    public synchronized void addElement(E obj) {
        modCount++;
        //扩容判断及操作
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }
20.removeElement方法和removeAllElements方法

    public synchronized boolean removeElement(Object obj) {
        modCount++;
        int i = indexOf(obj);
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }

    public synchronized void removeAllElements() {
        modCount++;
        // Let gc do its work
        for (int i = 0; i < elementCount; i++)
            elementData[i] = null;

        elementCount = 0;
    }
21.toArray方法

    public synchronized Object[] toArray() {
        return Arrays.copyOf(elementData, elementCount);
    }
该方法返回一个新的数组,数组中的元素按照Vector中的第一个到最后一个顺序排列,修改返回的数组不会影响原Vector中的数据。

22.get方法

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

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

        return elementData(index);
    }
23.set方法

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

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
set方法就是给数组的指定下标成员重新赋值。

24.add方法

    //首先进行扩容判断
    //给数组的elementCount++位置赋值为e
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

    //给index下标成员重新赋值
    public void add(int index, E element) {
        insertElementAt(element, index);
    }
25.remove方法

    //删除指定位置的元素
    //原理:将index+1位置开始到末尾的元素向前移动一位,最后一位赋值为null,GC进行回收
    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;
    }

    //删除指定内容的元素,删除匹配的第一个元素
    //原理:将匹配的第一个元素的位置下标加1开始到末尾的元素向前移动一位,最后一位赋值为null,GC进行回收
    public boolean remove(Object o) {
        return removeElement(o);
    }
26.clear方法

    public void clear() {
        removeAllElements();
    }
将数组所有元素引用设置了null,Vector的元素个数置为0;

27.iterator方法和listIterator方法
这两个方法同ArrayList中两个方法,不同点是进行了同步操作。在执行iterator或listIterator方法时,如果有线程从结构上做了修改(指任何添加或删除一个或多个元素的操作,或者显式调整底层数组的大小,仅仅设置元素的值不是结构上的修改),这两个方法会fail-fast,将会抛出ConcurrentModificationException。迭代器的快速失败行为无法得到保证,因为一般来说,不可能对是否出现不同步并发修改做出任何硬性保证。快速失败操作会尽最大努力抛出ConcurrentModificationException。因此,为提高此类操作的正确性而编写一个依赖于此异常的程序是错误的做法,正确做法是:ConcurrentModificationException应该仅用于检测bug。抛异常就是为了避免数据问题而存在的,其实就是检查modCount是否是期望值,如果不是,则说明Vector数组被从结构上修改了。这里是经常会遇到的问题,使用Java的For Each方式遍历元素时删除匹配的元素,会抛出ConcurrentModificationException。Java中的For Each实际上使用的是iterator进行处理的,而iterator是不允许集合在iterator使用期间删除的。

小结:
1.Vector底层也是基于动态数组的数据结构。
2.Vector在每次增加元素时,都要进行扩容判断,扩容时都要确保足够的容量。当容量不足以容纳当前的元素个数时,就设置新容量为旧的容量的2倍或旧容量加增长因子大小,如果新容量还不够,则新容量为最大容量。从中可以看出,当容量不够时,都要将原来的元素拷贝到一个新的数组中,耗时而且还需要重新分配内存,因此建议在事先能确定元素数量的情况下,明确指明容量大小。
3.Vector基于数组实现,可以通过下标索引直接查找到指定位置的元素,因此查找效率高,但每次插入或删除元素,就要大量地移动元素,效率低。

4.Vector是线程安全的,方法会进行同步,相对于ArrayList来说效率相对低,建议在非同步的情况下使用ArrayList。
Java技术分享微信公众号:JavaQ,公众号最新文章第一时间同步更新!欢迎围观!

 

0
1
分享到:
评论

相关推荐

    Vector-XCP 源代码

    "Vector-XCP 源代码" 是一个与嵌入式汽车电子控制单元(ECU)开发相关的源代码包,其中包含了XCP(eXtended Calibration Protocol)协议的相关实现和文档。XCP是一种广泛用于ECU标定和数据采集的标准通信协议,特别...

    vector源代码下载

    《深入理解C++标准库中的`vector`容器》 在C++标准库中,`std::vector`是一个非常重要的容器,它提供了动态数组的功能。在本文中,我们将深入解析一个自定义实现的`vector`类模板,以帮助我们更好地理解和应用`std:...

    VECTOR的CCP源码(CAN标定协议代码)

    VECTOR的can标定协议代码.只需稍微修改即实现通过canape实现ccp相关命令功能.

    Vector CCP协议实现C源码

    Vector CCP协议实现源码,ASAM CCP 2.1 Specification,Reference Documentation for the CCP Driver

    stl之vector带注释

    SGI STL之vector源码,带注释

    vector用法的源代码资源

    在C++编程中,`std::...在实际编程中,熟练掌握`vector`的使用能够极大地提高代码的效率和可读性。通过以上讲解,你应该对`vector`有了更深入的理解。在实际项目中,根据需求选择合适的容器,是优化代码性能的关键。

    vector 的 CCP 源码

    vector 公司网上的 ccp 源码,协议文档,样例和 canape

    vector源码.cpp

    vector源码.cpp,运用c++实现容器vector的编写

    vector中的排序的源代码资源

    总的来说,`vector`的排序功能是C++编程中常用的操作之一,通过`std::sort`函数和自定义比较函数,我们可以轻松地实现各种排序需求。同时,了解其背后的性能影响对于优化代码至关重要。在分析和解决问题时,理解这些...

    CCP.rar_Vector的ccp协议原码_dueo1k_vector

    Vector基于CAN的标定协议原码及例程说明文档

    Vector_CCP.zip_CCP vector_Vector的CCP_vctor ccp协议

    Vector的CCP协议源代码实现的样例和文档。

    VECTOR标定开发解决方案

    2. **ECU标定代码实现**:通过使用Vector公司的CANbedded等工具来实现ECU中的标定代码。 3. **测量标定工具**:CANape是一种功能强大的测量和标定工具,可以实现对ECU的实时监控和标定操作。 4. **高性能标定测量...

    vector1_STL_C++_vector_

    在C++编程语言中,标准模板库(Standard Template Library,简称STL)是不可或缺的一部分,它提供了一系列高效、可重用的数据结构和算法。...理解和熟练运用`vector`是成为合格的C++程序员的关键步骤之一。

    Vector Cast使用手册

    1. **创建测试项目**:首先,你需要在Vector Cast中创建一个新的测试项目,指定待测试的源代码目录和编译设置。 2. **生成测试代码**:Vector Cast支持自动生成测试代码,只需选择要测试的函数,系统会自动生成相应...

    VectorMagic.rar

    图形是量化的软件很多,用过AlgoLab Photo Vector,以及著名的r2v32。相较而言,这款vectorMagic更为强大,自动曲线平滑,还能筛选颜色输出。支持多种格式,eps,ai,dxf,cdr,psd等。重点还是免费的,值得图形处理...

    C++ STL VECTOR的实现

    c++的STL的vector的一个实现。使用了c++11的大部分特性,包含vector的几乎所有功能。仅作学习之用。

    单元测试 Vector Cast Train资料

    3. **测试生成**:Vector Cast可以自动生成测试用例,通过分析源代码来确定可能的边界条件和异常情况,减少手动编写测试的工作量。 4. **代码覆盖率**:Vector Cast提供代码覆盖率报告,显示被测试代码的行覆盖、...

    Vector初始化的各种写法

    如果数据源是其他容器,如列表或数组,可以使用迭代器来初始化Vector。在C++中: ```cpp std::list&lt;int&gt; source = {...}; std::vector&lt;int&gt; vec(source.begin(), source.end()); ``` 6. **使用工厂方法**: ...

    XCP Basic Driver.rar_Xcp 标定_leathertjb_vector XCP_vector xcp bas

    通过深入理解这个驱动的源代码,我们可以学习到如何与硬件接口交互,如何处理XCP报文,以及如何集成到VECTOR的标定环境中。 总的来说,"XCP Basic Driver.rar"提供的资源对于理解XCP协议和在VECTOR平台上进行标定...

    java vector 使用实例

    `vectorTest`可能是包含`Vector`使用实例的源代码文件,它可能演示了上述操作的实际应用。通过阅读和分析这个文件,你可以更好地理解`Vector`在实际编程中的使用情况。 总结起来,`Vector`在Java中提供了一种线程...

Global site tag (gtag.js) - Google Analytics