最近在看Vector与ArrayList的源码,看下他们的区别与联系。

  1. Vector是线程安全的集合类,ArrayList并不是线程安全的类。Vector类对集合的元素操作时都加了synchronized,保证线程安全。
  2. Vector与ArrayList本质上都是一个Object[] 数组,ArrayList提供了size属性,Vector提供了elementCount属性,他们的作用是记录集合内有效元素的个数。与我们平常调用的arrayList.size()和vector.size()一样返回的集合内有效元素的个数。
  3. Vector与ArrayList的扩容并不一样,Vector默认扩容是增长一倍的容量,Arraylist是增长50%的容量。
  4. Vector与ArrayList的remove,add(index,obj)方法都会导致内部数组进行数据拷贝的操作,这样在大数据量时,可能会影响效率。
  5. Vector与ArrayList的add(obj)方法,如果新增的有效元素个数超过数组本身的长度,都会导致数组进行扩容。

  先看下他们的源码是怎么定义内部数据存储的:

 private static final long serialVersionUID = 8683452581122892189L;

     /**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10; /**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {}; /**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
* DEFAULT_CAPACITY when the first element is added.
*/
private transient Object[] elementData; /**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;

这是ArrayList的定义,他首先定义了他的初始化容量为10

private static final int DEFAULT_CAPACITY = 10

这里应该看到了数据存储是放在Object数组里的

private transient Object[] elementData

定义了数据的长度size

The size of the ArrayList (the number of elements it contains)

再看看Vector的定义:

  /**
* The array buffer into which the components of the vector are
* stored. The capacity of the vector is the length of this array buffer,
* and is at least large enough to contain all the vector's elements.
*
* <p>Any array elements following the last element in the Vector are null.
*
* @serial
*/
protected Object[] elementData; /**
* The number of valid components in this {@code Vector} object.
* Components {@code elementData[0]} through
* {@code elementData[elementCount-1]} are the actual items.
*
* @serial
*/
protected int elementCount; /**
* The amount by which the capacity of the vector is automatically
* incremented when its size becomes greater than its capacity. If
* the capacity increment is less than or equal to zero, the capacity
* of the vector is doubled each time it needs to grow.
*
* @serial
*/
protected int capacityIncrement;

Vector定义了数组

protected Object[] elementData;

有效元素个数

protected int elementCount

Vector增长容量,默认0

protected int capacityIncrement

Vector和ArrayList在元素超过初始大小时扩容是不一样的,但是也不像网上说的Vector增长是按一倍增长,我觉得应该加默认两个字才对,Vector中的元素个数超过了初始化容量的话,默认确实会增长一倍,请看代码:

  /**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
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);
}

代码里在判断增长容量(简称增量)参数时如果增量大于0时,是会按增量进行扩容的,否则的话才会增加一倍的容量到数组中。

而Vector在初始化加载构造函数时,开发人员是可以指定其增量的大小的,并不是必须要根据增加一倍的规则进行增加。还是看代码:

  public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
} /**
* Constructs an empty vector with the specified initial capacity and
* with its capacity increment equal to zero.
*
* @param initialCapacity the initial capacity of the vector
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public Vector(int initialCapacity) {
this(initialCapacity, 0);
} /**
* Constructs an empty vector so that its internal data array
* has size {@code 10} and its standard capacity increment is
* zero.
*/
public Vector() {
this(10);
}

可以看到在构造函数中已经表明,可以指定其增量的大小,如果没有指定默认0。数组的初始化大小为10。

但是ArrayList就不可以进行增量的修改指定。还是看代码:

 /**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);  //看这里
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}

首先在构造函数中,ArrayList就没有提供相应的设置增量的方法,而扩容方法grow中直接就对数组进行增量50%的操作了,并没有相应的参数设置或判断增量的大小。

在上边都提到了一个静态常量是private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这个常量是数组扩容的最大长度,但是为什么-8呢我看了上边的描述,感觉应该是:

Some VMs reserve some header words in an array.

有些虚拟机会在数组头部加入一些信息,如果还是设置最大的话,可能会导致OOM

这就是Vector和ArrayList在扩容及成员变量方面的区别及联系了。

接下来我们看看他们的源码中插入、删除等方法为什么说和LinkedList相比要慢

先看代码:

 1 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++;
}

Vector集合在add(int index, E element)时实际上调用了insertElementAt方法,他和删除方法实际上都是对数组进行了copy,所以在大数据量时可能会导致效率降低。ArrayList也是这样的情况。

但是在增加调用add(E e)方法时,其实就是在数组中追加数据了,如果追加数据的长度大于实际数组长度的话,会进入到grow扩容方法进行扩容。

Vector和ArrayList都提供了trimToSize()方法,这个方法是对数组容量进行缩减的方法。在这个方法中,调用方法时会对数组的元素容量及数组本身长度进行判断,如果数组内实际元素的个数比数组本身的长度少的话,调用这个方法会将数组缩减到元素个数大小。在数据量大的时候可以考虑这样做,这样可以节省不必要的空间浪费。看代码:

 public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = Arrays.copyOf(elementData, size);
}
}

Vector本身提供了一个同步方法叫setSize方法,该方法可以对当前集合进行长度设置。如果设置的长度比当前元素个数要大的话会进行判断是否需要扩容,如果不是,在给定的Size值外的元素将被置为空值。

看代码:

 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;
}

这大体上就是Vector和ArrayList的区别

ps:以上只是个人理解,如有不对请指正。

Vector与ArrayList 的理解的更多相关文章

  1. Vector和ArrayList的比较

    今天研究了一下Vector和ArrayList的源码,又加深了对这两个类的理解. List接口下一共实现了三个类:ArrayList,Vector,LinkedList.LinkedList就不多说了 ...

  2. 【转】java 容器类使用 Collection,Map,HashMap,hashTable,TreeMap,List,Vector,ArrayList的区别

    原文网址:http://www.360doc.com/content/15/0427/22/1709014_466468021.shtml java 容器类使用 Collection,Map,Hash ...

  3. [Java语言] HashMap,HashSet,Hashtable,Vector,ArrayList 的关系 <转>

    这么几个比较常用的但是比较容易混淆的概念同出于 java.util 包.本文仅作几个类的浅度解析. (本文基于JDK1.7,源码来自openjdk1.7.) ├── Collection │ ├── ...

  4. Java中Vector和ArrayList的区别

    首先看这两类都实现List接口,而List接口一共有三个实现类,分别是ArrayList.Vector和LinkedList.List用于存放多个元素,能够维护元素的次序,并且允许元素的重复.3个具体 ...

  5. Java 中Iterator 、Vector、ArrayList、List 使用深入剖析

    标签:Iterator Java List ArrayList Vector 线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些 ...

  6. Vector 和 ArrayList 区别

    1.Vector是多线程安全的,而ArrayList不是,如果只有一个线程会访问到集合,那最好是使用ArrayList,因为它不考虑线程安全,效率会高些:Vector是旧的,是java一诞生就提供了的 ...

  7. Java 常用数据结构深入分析(Vector、ArrayList、List、Map)

    线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以 ...

  8. hashtable,hashMap,vector和ArrayList

    关于vector,ArrayList,hashMap和hashtable之间的区别 vector和ArrayList:  线程方面:  vector是旧的,是线程安全的  ArrayList是java ...

  9. 【转】Java中Vector和ArrayList的区别

    首先看这两类都实现List接口,而List接口一共有三个实现类,分别是ArrayList.Vector和LinkedList.List用于存放多个元素,能够维护元素的次序,并且允许元素的重复.3个具体 ...

随机推荐

  1. 2019 中钢网java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.中钢网等公司offer,岗位是Java后端开发,因为发展原因最终选择去了中钢网,入职一年时间了,也成为了面试官 ...

  2. BZOJ1040: [ZJOI2008]骑士(奇环树,DP)

    题目: 1040: [ZJOI2008]骑士 解析: 假设骑士\(u\)讨厌骑士\(v\),我们在\(u\),\(v\)之间连一条边,这样我们就得到了一个奇环树(奇环森林),既然是一颗奇环树,我们就先 ...

  3. spark源码阅读--shuffle过程分析

    ShuffleManager(一) 本篇,我们来看一下spark内核中另一个重要的模块,Shuffle管理器ShuffleManager.shuffle可以说是分布式计算中最重要的一个概念了,数据的j ...

  4. Xcode11 Developer Tool中没了Application Loader

    升级Xcode11之后不少人发现在Open Developer Tool中没了Application Loader. 那么如果我们还想用该怎么办呢? 先这样 找个老版的Xcode–>Conten ...

  5. 虚拟环境和pip相关的命令

    # 虚拟环境 mkvirtualenv # 创建虚拟环境 rmvirtualenv # 删除虚拟环境 workon # 进入虚拟环境.查看所有虚拟环境 deactivate # 退出虚拟环境 eg: ...

  6. jackson 学习资料

    源代码托管地址 https://github.com/FasterXML/jackson https://github.com/FasterXML/jackson-docs http://www.st ...

  7. 记录下Hbuilder 打包IOS发布时 总是提示错误:ios prifile文件与私钥证书匹配 的问题

    最近两天,新的APP准备要上线,然后打包正式发布版 时,总是提示不匹配 证书照hbuilder里面的文档 一样也不行,然后百度了N种方法,都是不行,而且也比较少搜索到相关问题. 后来都是谷歌了下,找到 ...

  8. Python数据分析 之时间序列基础

    1. 时间序列基础 import numpy as np import pandas as pd np.random.seed(12345) import matplotlib.pyplot as p ...

  9. C#8.0——异步流(AsyncStream)

    异步流(AsyncStream) 原文地址:https://github.com/dotnet/roslyn/blob/master/docs/features/async-streams.md 注意 ...

  10. Java面向对象 练习(类、对象、方法)

    知识点:构造方法.继承.方法重载.方法重写 一. 定义一个点(Point)类,用来表示三维空间中的点(有三个坐标),要求如下: 1.可以生成具有特定坐标的点对象(构造方法): 2.提供可以设置三个坐标 ...