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,是线程安全的。
Java数据结构漫谈-Vector的更多相关文章
- Java数据结构漫谈-Stack
Stack(栈)是一种比较典型的数据结构,其元素满足后进先出(LIFO)的特点. Java中Stack的实现继承自Vector,所以其天然的具有了一些Vector的特点,所以栈也是线程安全的. cla ...
- Java 数据结构之vector
Vector 实现了一个动态数组.是可实现自动增长的对象数组. vector和arraylist的比较: 1.都是采用数组格式存储数据,索引数据块插入数据慢 2.ArrayList会比Vector快, ...
- Java数据结构漫谈-LinkedList
同样是List的数据结构,LinkedList是使用了前后指针,指明节点的方式来表示链表的,这与之前介绍的ArrayList http://www.cnblogs.com/yakovchang/p/j ...
- Java数据结构漫谈-ArrayList
ArrayList是一个基于数组实现的链表(List),这一点可以从源码中看出: transient Object[] elementData; // non-private to simplify ...
- Java数据结构之线性表(2)
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- Java数据结构之线性表
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- Java数据结构和算法 - 数组
Q: 数组的创建? A: Java中有两种数据类型,基本类型和对象类型,在许多编程语言中(甚至面向对象语言C++),数组也是基本类型.但在Java中把数组当做对象来看.因此在创建数组时,必须使用new ...
- (6)Java数据结构-- 转:JAVA常用数据结构及原理分析
JAVA常用数据结构及原理分析 http://www.2cto.com/kf/201506/412305.html 前不久面试官让我说一下怎么理解java数据结构框架,之前也看过部分源码,balab ...
- 自己动手实现java数据结构(一) 向量
1.向量介绍 计算机程序主要运行在内存中,而内存在逻辑上可以被看做是连续的地址.为了充分利用这一特性,在主流的编程语言中都存在一种底层的被称为数组(Array)的数据结构与之对应.在使用数组时需要事先 ...
随机推荐
- 读书笔记_Effective_C++_条款二十二:将成员变量声明为private
1.格式统一 在调用的时候,不会去想有没有(),一律是有get(),或者set()之类的. 2.封装 能直接访问得越少,表明封装性越高, 封装性越高,我们的顾虑就少了, 例如:我们a.data*0.9 ...
- 原生拖拽,拖放事件(drag and drop)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Chrome调试nodejs
1.安装node-inspector 命令: npm install -g node-inspector 2.nodemon --debug xxx.js启动项目(如果使用--debug-brk 就会 ...
- CentOS(Linux) - SVN使用笔记(二) - 创建SVN仓库及下载仓库到本地
1.安装: 参考文章 CentOS(Linux) - SVN使用笔记(一) - 安装SVN过程及开启和关闭svn服务指令 2.创建仓库 #创建项目目录 mkdir /usr/svn#进入目录cd / ...
- jquery实现弹出即消失的提示层
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Flask学习记录之Flask-Mail
Flask-Mail可以连接到配置中的SMTP服务器,进行邮件发送,如果没有进行SMTP服务器的配置,将会默认连接到localhost上的 一.配置及初始化 (1)flask应用配置 #配置选项 MA ...
- http head
Accept HTTP_ACCEPT Accept-Charset HTTP_ACCEPT-CHARSET Accept-Encoding HTTP_ACCEPT-ENCODING Accept-La ...
- iOS触摸事件深度解析-备用
概述 本文主要解析从我们的手指触摸苹果设备到最终响应事件的整个处理机制.本质上讲,整个过程可以分为两个步骤: 步骤1:找目标.在iOS视图层次结构中找到触摸事件的最终接受者: 步骤2:事件响应.基于i ...
- jquery serialize的使用
serialize() 方法通过序列化表单值,创建 URL 编码文本字符串. <!DOCTYPE html> <html lang="en"> <he ...
- Linux 杀死挂起的进程
在用管理员执行一个命令后,用Ctrl+Z把命令转移到了后天.导致无法退出root的. 输入命令:exit终端显示:There are stopped jobs. 解决方法:方法一.输入命令:jobs终 ...