浅谈Vector

在之前的文章中,我们已经说过线程不安全的ArrayList和LinkedList,今天我们来讲讲一个线程安全的列表容器,他就是Vector,他的底层和ArrayList一样使用数组来实现,不过不同于ArrayList的线程不安全,Vector中的公开方法基本都是带有synchronized关键字的,虽然有些方法是非同步的,但内部总是会调用同步的方法保证整个方法的线程安全,即使是subList方法返回的子列表也是通过Collections类的synchronizedList来保证返回的子列表也是线程安全的:

public synchronized List<E> subList(int fromIndex, int toIndex) {
    return Collections.synchronizedList(super.subList(fromIndex, toIndex), this);
}

下面我们来介绍Vector的构造方法,Vector为我们提供了四种构造方法,前三种,基本就是无参调用单参,并传递一个默认容量值,单参调用双参,并传递一个默认容量值

Vector();

public Vector() {
    //调用单参的构造方法,并传递一个初始容量值10
    this(10);
}

Vector(int initialCapacity);

public Vector(int initialCapacity) {
    //调用双参的构造方法,并传递一个默认增量值0,增量值为0,代表每次扩容,容量会直接翻倍
    this(initialCapacity, 0);
}

Vector(int initialCapacity, 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;
}

第四种构造方法,则是根据传入的集合对象来初始化矢量列表的元素

Vector(Collection<? extends E> c);

public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    // c.toArray might (incorrectly) not return Object[] (see 6260652)
    //如果通过toArray方法转换得到的数组类型不是Object[],则进行二次转化
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

在方法讲解之前,我们先来看看Vector的扩容机制,Vector提供了一个公开方法ensureCapacity(int minCapacity),通过该方法你可以传入一个列表需要的最小容量值(但最终生成的新容量可能并不是这个值),然后做一个简单的校验,进一步调用内部私有的ensureCapacityHelper(int minCapacity)方法进行进一步判断,如果该值小于列表当前的列表容量(非列表元素总数),不会进入到扩容方法grow中,进入grow方法后就开始了具体的扩容流程,具体请看下面的源码:

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 void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    //按内置规则扩容获得新的容量值,如果增量变量为0,容量翻倍,否则增加增量变量指定的增量值
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
    //将新的容量值与传入的最小容量作比较,如果最小容量值大于新的容量值,则将最小容量值作为新的容量值,否则使用内置扩容规则获得的容量值
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    //最后将容量值与数组最大容量值(最大整型值-8)做比较
    //数组作为一个对象,需要一定的内存存储对象头信息,对象头信息最大占用内存不可超过8字节
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    //使用新容量和原列表生成新的列表并将元素进行拷贝,内部最终调用System.arraycopy方法进行元素拷贝
    elementData = Arrays.copyOf(elementData, newCapacity);
}

讲完Vector的扩容规则,下面正式进入Vector中方法的讲解

add(E element); addElement(E element);

这个两个方法都是往矢量列表尾部插入新的元素,都是同步方法,不同点是add的返回值为布尔类型,而addElement没有返回值

add(int index, E element); insertElementAt(E element, int index);

这两个方法可以说是完全一致,在add方法内只是进行了insertElementAt方法的调用,虽然add是非同步方法,但insertElementAt是一个同步方法

addAll([int index,] Collection<? extends E> c);

该方法用于往矢量列表中存入集合中的所有元素,该方法存在单参和双参两个重载方法,都是同步方法,单参方法直接往尾部插入,双参方法可以在指定索引位置插入

remove(int index);

该方法用于删除矢量列表中指定索引位置的值,并返回被删除的元素,该方法是同步方法

remove(Object o); removeElement(Object o); removeElementAt(int index);

这三个方法都是用于删除矢量列表中的元素,其中remove是非同步的,其余两个方法都是同步的,但在remove方法调用了同步的removeElement方法,在removeElement方法中先是通过indexOf方法查找待删除元素的索引,找到则调用removeElementAt方法删除指定索引位置的元素值

removeAll(Collection<?> c)

该方法用于删除传入集合中指定的所有元素,是一个同步方法

retainAll(Collection<?> c);

该方法用于保留传入集合中指定的所有元素,即删除指定集合之外的所有元素,该方法是一个同步方法

clear(); removeAllElements();

这两个方法都是用于删除矢量列表中的所元素,其中clear方法是非同步的,内部调用了同步的removeAllElements方法

removeRange(int fromIndex, int toIndex);

该方法用于移除矢量列表中指定索引范围的所有元素,该方法是一个同步方法

removeIf(Predicate<? super E> filter);

该方法用于移除矢量列表中符合指定条件的元素,该方法是一个同步方法,下面使用匿名内部类和Lambda做一个简单的使用演示:

Vector<Integer> list = new Vector<>();
list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
System.out.println(list);
//如果不会使用Lambda表达式,则需要new Predicate接口对象并实现内部的test方法
list.removeIf(x -> x < 3);
System.out.println(list);
//对应的运行结果
[1, 2, 3, 4, 5]
[3, 4, 5]

set(int index, E element); setElementAt(E element, int index);

这两个方法都是用于替换矢量列表中指定索引位置的元素值,都是同步方法,不同点是set方法返回被替换的元素值,而setElementAt没有返回值

replaceAll(UnaryOperator operator);

该方法用于对矢量列表中的所有元素进行指定钩子函数的操作,并且会保存对元素所做的修改,该方法是一个同步方法,下面使用匿名内部类结合Lambda表达式做一个简单的使用演示:

Vector<Integer> list = new Vector<>();
list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
System.out.println(list);
//或者使用UnaryOperator接口创建匿名内部类,并实现apply方法亦可
list.replaceAll(x -> x + 2);
System.out.println(list);
//对应的运行结果
[1, 2, 3, 4, 5]
[3, 4, 5, 6, 7]

forEach()

该方法用于对矢量列表中的所有元素进行指定钩子函数的操作,但是不会保存对元素所做的修改,该方法是一个同步方法,下面做简单演示:

Vector<Integer> list = new Vector<>();
list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
System.out.println(list);
//或者使用Consumer接口创建匿名内部类,并实现accept方法亦可
list.forEach(x -> System.out.println(x += 2));
System.out.println(list);
//对应的运行结果
[1, 2, 3, 4, 5]
3
4
5
6
7
[1, 2, 3, 4, 5]

get(int index); elementAt(int index);

这两个方法是一样的,用于返回矢量列表中指定位置的元素值,都是同步方法

elements();

该方法用于返回矢量列表的枚举对象,该方法是一个同步方法,可以使用返回的枚举对象进行简单迭代遍历,下面是简单应用:

Vector<Integer> list = new Vector<>();
list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
Enumeration<Integer> elements = list.elements();
while (elements.hasMoreElements()){
    System.out.println(elements.nextElement());
}

firstElement(); lastElement();

这两个方法分别用于返回矢量列表中的首元素和尾元素,都是同步方法

indexOf(Object o); lastIndexOf(Object o);

这两个方法分别用于返回矢量列表中第一次出现和最后一次出现指定元素的索引值,都是同步方法

lastIndexOf(Object o, int index);

该方法在lastIndexOf(Object o)的基础上添加了一个索引值,用于在指定索引值之前的位置查找最后一次出现指定元素的索引值,该方法是同步方法

iterator();

该方法用于返回矢量列表的普通迭代器对象,迭代器提供了hasNext,next,remove,forEachRemaining方法用于对元素进行操作,iterator方法是是一个同步方法

listIterator([int index]);

该方法用于返回矢量列表的增强迭代器对象,提供了普通迭代器的所有功能,此外还有hasPrevious,nextIndex,previousIndex,previous,set,add方法,而且还可以通过index参数指定起始迭代位置,listIterator方法是一个同步方法

spliterator();

该方法用于将矢量列表转化为可分割的数组对象,转化后的对象可以多次调用trySplit进行分割(五五分成),适合多线程的方式对大型矢量列表进行操作,简单演示拆分过程:

Vector<Integer> list = new Vector<>();
list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
list.add(6);list.add(7);list.add(8);list.add(9);list.add(0);
Spliterator<Integer> part1 = list.spliterator();
Spliterator<Integer> part2 = part1.trySplit();
Spliterator<Integer> part3 = part1.trySplit();
Spliterator<Integer> part4 = part2.trySplit();
part1.forEachRemaining(x-> System.out.print(x+" "));
System.out.println();
part2.forEachRemaining(x-> System.out.print(x+" "));
System.out.println();
part3.forEachRemaining(x-> System.out.print(x+" "));
System.out.println();
part4.forEachRemaining(x-> System.out.print(x+" "));
//对应的操作结果
8 9 0
3 4 5
6 7
1 2

capacity();

该方法用于返回矢量列表的容量值(elementData.length),该方法是一个同步方法

clone();

该方法用于返回一个矢量列表的浅克隆对象,该方法是同步方法

contains(Object o);

该方法用于判断矢量列表中是否含有指定元素,该方法是一个非同步方法,但内部调用同步的indexOf方法

containsAll(Collection<?> c);

该方法用于判断矢量列表中是否包含传入集合的所有元素,该方法是一个同步方法

copyInto(Object[] array);

该方法用于将矢量列表的全部元素值拷贝到传入的数组中,该方法是一个同步方法

equals(Object o);

该方法用于判断传入元素是否与当前元素相等(值相等,不一定非要是地址相等),该方法是同步方法

isEmpty();

该方法用于判断矢量列表中是否存在元素,主要根据elementCount属性值来判断,该方法是同步方法

setSize(int size);

该方法用于将矢量列表的元素总数控制在传入的size之内,如果size大于当前列表元素总数(elementCount),则将elementCount-size范围的null当做列表元素(从这里可以看出矢量列表中的元素存在与否不能根据是否为null来判断,而需要根据elementCount来判断),如果传入的size小于列表元素总数,则将size-elementCount的值都置为null,最后都将elementCount=size值,该方法是一个同步方法

size();

该方法用于返回矢量列表的元素总数(elementCount),该方法是一个同步方法

sort(Comparator<? super E> c);

该方法用于将矢量列表里的所有元素按照钩子函数的规则进行排序,该方法是一个同步方法,下面对该方法做简单演示:

Vector<Integer> list = new Vector<>();
list.add(1);list.add(4);list.add(5);list.add(2);list.add(3);
list.add(8);list.add(9);list.add(0);list.add(6);list.add(7);
System.out.println(list);
//或者使用Comparator接口创建匿名内部类,并实现compare方法亦可
list.sort((o1,o2) -> o1 - o2);
System.out.println(list);

subList(int fromIndex, int toIndex);

该方法用于返回当前矢量列表指定范围内的子列表对象,该方法是一个同步方法,要注意的是最终返回的列表对象依旧是整个矢量列表对象,不过是添加了偏移量属性,所以对子列表的操作都会反映到父列表中

toArray(T[] a);

该方法用于获取矢量列表的数组对象,并转化为参数对应的数组类型,该方法是一个同步方法,以下为该方法的简单使用:

//如果直接调用list.toArray()方法,等同于list.toArray(new Object[0]);
String[] strs = list.toArray(new String[0]);

trimToSize();

该方法用于将矢量列表的容量调整为列表元素总数,调整中会生成新的数组对象,该方法为同步方法

如果对你有帮助,点个赞,或者打个赏吧,嘿嘿

整理不易,请尊重博主的劳动成果

浅谈Vector的更多相关文章

  1. 浅谈 Vector

    目录 浅谈Vector 1.容器基本操作 2.vector 初始化 3.vector的赋值与swap 4.vector的增删改除 1.增加元素 2.访问元素 3.删除元素 4.元素的大小 浅谈Vect ...

  2. 浅谈Vector、ArrayList、LinkedList

    下图是Collection的类继承图 从图中可以看出:Vector.ArrayList.LinkedList这三者都实现了List 接口.所有使用方式也很相似,主要区别在于实现方式的不同,所以对不同的 ...

  3. 由jtable浅谈vector<vector<Object>>的用法(转自a718515028的专栏)

    以前只用过vector<Object>  ,但是在做从数据库导出数据放到jtable中时,发现还有个vector<vector<Object>>的用法. 先说jta ...

  4. 浅谈C++ STL vector 容器

    浅谈C++ STL vector 容器 本篇随笔简单介绍一下\(C++STL\)中\(vector\)容器的使用方法和常见的使用技巧.\(vector\)容器是\(C++STL\)的一种比较基本的容器 ...

  5. 浅谈JAVA集合框架

    浅谈JAVA集合框架 Java提供了数种持有对象的方式,包括语言内置的Array,还有就是utilities中提供的容器类(container classes),又称群集类(collection cl ...

  6. C++ STL中的常用容器浅谈

    STL是C/C++开发中一个非常重要的模板,而其中定义的各种容器也是非常方便我们大家使用.下面,我们就浅谈某些常用的容器.这里我们不涉及容器的基本操作之类,只是要讨论一下各个容器其各自的特点.STL中 ...

  7. 浅谈Java的集合框架

    浅谈Java的集合框架 一.    初识集合 重所周知,Java有四大集合框架群,Set.List.Queue和Map.四种集合的关注点不同,Set 关注事物的唯一性,List 关注事物的索引列表,Q ...

  8. 浅谈java类集框架和数据结构(2)

    继续上一篇浅谈java类集框架和数据结构(1)的内容 上一篇博文简介了java类集框架几大常见集合框架,这一篇博文主要分析一些接口特性以及性能优化. 一:List接口 List是最常见的数据结构了,主 ...

  9. 浅谈压缩感知(二十四):压缩感知重构算法之子空间追踪(SP)

    主要内容: SP的算法流程 SP的MATLAB实现 一维信号的实验与结果 测量数M与重构成功概率关系的实验与结果 SP与CoSaMP的性能比较 一.SP的算法流程 压缩采样匹配追踪(CoSaMP)与子 ...

随机推荐

  1. 基于 websocket 的多端桥接平台

    我们现在的业务是基于新闻客户端实现的,都要经过新闻客户端的环境,进行前后端数据上的交互.但是我们在调试过程中,非常的不方便. 通常使用的工具有:modheader, postman, fiddler ...

  2. GitHub 热点速览 Vol.13:近 40k star 计算机论文项目再霸 GitHub Trending 榜

    作者:HelloGitHub-小鱼干 摘要:"潮流是个轮回",这句话用来形容上周的 GitHub Trending 最贴切不过.无论是已经获得近 40k 的高星项目 Papers ...

  3. ubuntu初始化root密码

    输入 sudo passwd root 输入两遍密码.

  4. 【翻译】如何使用 OpenVINO 来优化 OpenCV

    本文翻译自 Vishwesh Shrimali 的  "Using OpenVINO with OpenCV" 原文链接: https://www.learnopencv.com/ ...

  5. 3D画廊

    3D画廊 之前我都是写的学习的内容,我在写这些教程时遇到有趣的炫酷的小例子也会专门拿出来写一篇文章,今天就写一个酷炫的小例子,叫3D画廊,它是属于ViewPage的进阶版. 此项目下载地点:https ...

  6. 同源策略与JSONP劫持原理

    同源策略 浏览器中有两个安全机制,一个浏览器沙盒(Sandbox),另一个就是同源策略(Same Origin Policy,简称SOP) ,下面介绍同源策略.同源是指同协议.同域名.同端口,必须三同 ...

  7. python接口调用把执行结果追加到测试用例中

    python操作excel的三个工具包如下,注意,只能操作.xls,不能操作.xlsx. xlrd: 对excel进行读相关操作 xlwt: 对excel进行写相关操作 xlutils: 对excel ...

  8. ArcGIS Desktop的安装

    1.双击ArcGIS Desktop安装目录下的Setup.exe. 2.点击“下一步”. 3.选择“我接受许可协议(A)”,点击“下一步”. 4.选择“完全安装”,点击“下一步”. 5.点击“更改” ...

  9. 一、配置Ubuntu网络设置大纲

    root@ubuntu:为我的Ubuntu系统,即 用户名@主机名: 1.改主机名 ifconfig查询本机IP地址vim  /etc/hostname进入i编辑更改,改完按esc键 然后:wq!保存 ...

  10. 运行redis数据库

    启动redis服务器:redis-server /usr/local/redis-5.0.5/etc/redis.conf 关闭: redis-cli shutdown启动客户端:进入bin文件夹,输 ...