[学习笔记]转载

Java集合类源码解析:Vector

 

引言

之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector
为什么说是它兄弟呢?因为从容器的构造来说,Vector 简直就是 ArrayList 的翻版,也是基于数组的数据结构,不同的是,Vector的每个方法都加了 synchronized 修饰符,是线程安全的。

类声明

用idea打开 Vector 的源码,不难发现,它的类声明跟 ArrayList 一模一样,都是继承了AbstractList,并且都实现了RandomAccess接口,遍历元素用for循环的效率要优于迭代器。

 * @author  Lee Boynton
* @author Jonathan Payne
* @see Collection
* @see LinkedList
* @since JDK1.0
*/
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

值得说明的是,从注释上来看,Vector 是 JDK1.0版本就引进的,属于最古老的集合类的那一批,而ArrayList是 1.2才引进的,所以说,Vector才是哥哥,ArrayList是小弟,哈哈~~~~

基本变量和构造函数

基本变量

Vector 的基本变量有四个,分别是:

  • 底层数组
protected Object[] elementData;
  • 数组元素个数
protected int elementCount;
  • 增长的容量大小,如果这个值小于或等于0,扩容时会扩大 2 倍,
capacityIncrement
  • 最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

构造函数

//创建初识容量为10的数组,增长量0
public Vector() {
this(10);
}
//创建初识容量可变的数组,增长量为0
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
//创建初识容量可变的数组,可设置增长量
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(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);
}

看的出来,Vector的构造器和成员变量和ArrayList大同小异。

成员方法

扩容

Vector 与 ArrayList 虽然很类似,但在扩容大小这方面还是有区别的,ArrayList 默认扩容后的大小为原容量 的1.5倍,而Vector则是先判断增长量大小,如果是非正数,那就扩大为原来的2倍,看一下它的扩容方法:

//参数是最小需要的容量
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//如果增长量不大于0,扩容为2倍大小
//一般默认创建的容器都是不传增长量的,所以默认增长量是0,也就是默认直接扩容两倍
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;
}

添加

Vector的添加方法都是加上 synchronized关键字的,并且添加前检测容量,判断是否扩容:

//加入元素到数组结尾,同步的
public synchronized boolean add(E e) {
modCount++;
//检测容量
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
//检测容量大小,超过数组长度就做扩容
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
public void add(int index, E element) {
insertElementAt(element, index);
}
//插入对应索引的元素
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++;
}
public synchronized void addElement(E obj) {
modCount++;
//保证容量足够
ensureCapacityHelper(elementCount + 1);
//直接设置最后一个元素的数据
elementData[elementCount++] = obj;
}
//添加整个集合
public synchronized boolean addAll(Collection<? extends E> c) {
modCount++;
//把集合转为数组对象
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityHelper(elementCount + numNew);
//直接复制集合元素到数组后面
System.arraycopy(a, 0, elementData, elementCount, numNew);
elementCount += numNew;
return numNew != 0;
}
//在对应的索引处插入一个集合
public synchronized boolean addAll(int index, Collection<? extends E> c) {
modCount++;
if (index < 0 || index > elementCount)
throw new ArrayIndexOutOfBoundsException(index); Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityHelper(elementCount + numNew);
//计算要移动多少个元素
int numMoved = elementCount - index;
if (numMoved > 0)
//把插入位置后面的元素后移这么多位
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
//复制元素数组
System.arraycopy(a, 0, elementData, index, numNew);
elementCount += numNew;
return numNew != 0;
}

Vector的添加方法代码不是很复杂,跟ArrayList 一样,本质上都是对数组做插入数据的操作,不同的是,方法都加了synchronized 修饰,所以,它的添加方法都是线程安全的。

其他操作元素的方法也是这样的套路,这里不打算一一列举了,因为都跟ArrayList 差不多,另外,Vector 比 ArrayList 多了一个迭代方法

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 对比 ArrayList

最后,总结一下 Vector 和 ArrayList 的对比吧。

相同点:

  • 底层都是基于数组的结构,默认容量都是10;

  • 都实现了RandomAccess 接口,支持随机访问;

  • 都有扩容机制;

区别:

  • Vector 的方法有做同步操作,是属于线程安全的,而ArrayList 是非线程安全的;

  • Vector默认情况下扩容后的大小为原来的2倍,而ArrayList 是1.5倍;

  • Vector 比 ArrayList 多了一种迭代器 Enumeration;

虽然Vector相较ArrayList做了同步的处理,但这样也影响了效率,因为每次调用方法都要获取锁,所以,一般情况下,对集合的线程安全没有需求的话,推荐使用 ArrayList。

版权保护:本文为转载文章,原文地址:https://www.cnblogs.com/yeya/p/9970654.html

Java集合类源码解析:Vector的更多相关文章

  1. Java集合类源码解析:HashMap (基于JDK1.8)

    目录 前言 HashMap的数据结构 深入源码 两个参数 成员变量 四个构造方法 插入数据的方法:put() 哈希函数:hash() 动态扩容:resize() 节点树化.红黑树的拆分 节点树化 红黑 ...

  2. Java集合类源码解析:ArrayList

    目录 前言 源码解析 基本成员变量 添加元素 查询元素 修改元素 删除元素 为什么用 "transient" 修饰数组变量 总结 前言 今天学习一个Java集合类使用最多的类 Ar ...

  3. Java集合类源码解析:AbstractMap

    目录 引言 源码解析 抽象函数entrySet() 两个集合视图 操作方法 两个子类 参考: 引言 今天学习一个Java集合的一个抽象类 AbstractMap ,AbstractMap 是Map接口 ...

  4. Java集合类源码解析:LinkedHashMap

    前言 今天继续学习关于Map家族的另一个类 LinkedHashMap .先说明一下,LinkedHashMap 是继承于 HashMap 的,所以本文只针对 LinkedHashMap 的特性学习, ...

  5. Java集合类源码解析:AbstractList

    今天学习Java集合类中的一个抽象类,AbstractList. 初识AbstractList AbstractList 是一个抽象类,实现了List<E>接口,是隶属于Java集合框架中 ...

  6. 【转】Java HashMap 源码解析(好文章)

    ­ .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wra ...

  7. JDK8集合类源码解析 - HashSet

    HashSet 特点:不允许放入重复元素 查看源码,发现HashSet是基于HashMap来实现的,对HashMap做了一次“封装”. private transient HashMap<E,O ...

  8. Java——LinkedHashMap源码解析

    以下针对JDK 1.8版本中的LinkedHashMap进行分析. 对于HashMap的源码解析,可阅读Java--HashMap源码解析 概述   哈希表和链表基于Map接口的实现,其具有可预测的迭 ...

  9. java集合 源码解析 学习手册

    学习路线: http://www.cnblogs.com/skywang12345/ 总结 1 总体框架 2 Collection架构 3 ArrayList详细介绍(源码解析)和使用示例 4 fai ...

随机推荐

  1. vue防止按钮在短时间内被多次点击的方法

    vue组件 (function(){ let openDelay=false; Vue.directive('intervalclick', function(el,binding){ el.oncl ...

  2. js十大排序算法

    排序算法说明: (1)对于评述算法优劣术语的说明 稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面:不稳定:如果a原本在b的前面,而a=b,排序之后a可能会出现在b的后面: 内排序:所有排 ...

  3. 跟我一起学opencv 第四课之图像的基本操作

    1.图像是由像素组成的,所以修改了像素就可以实现图像的改变. 2先看灰度图像(单通道): *****2.获取灰度图像的像素值使用:  int gray = gray_src.at<uchar&g ...

  4. Spring:(二)DI依赖注入方式

    DI 依赖注入 DI(Dependency Injection)依赖注入,说简单一点就将类里面的属性在创建类的过程中给属性赋值,即将对象依赖属性(简单值,集合,对象)通过配置设值给该对象. 属性注入的 ...

  5. PBFT概念与Go语言入门(Tendermint基础)

    Tendermint作为当前最知名且实用的PBFT框架,网上资料并不很多,而实现Tendermint和以太坊的Go语言,由于相对小众,也存在资料匮乏和模糊错漏的问题.本文简单介绍PBFT概念和Go语言 ...

  6. Cron表达式详解【转】

    Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式: Seconds Minutes Hours DayofMonth Month ...

  7. Spring学习(一):理解IoC容器

    序言 记得刚毕业那会儿,出来招工作被问到Spring的核心时,都觉得简单的一笔,直接说不就是IoC(控制反转)和DI(依赖注入)么,然后省略一万字对两个名词的解释.最近空来整理了一下Spring中Io ...

  8. C# 插入超链接到PDF文档(3种情况)

    超链接可以实现不同元素之间的连接,用户可以通过点击被链接的元素来激活这些链接.具有高效.快捷.准确的特点.本文中,将分享通过C#编程在PDF文档中插入超链接的方法.内容包含以下要点: 插入网页链接 插 ...

  9. CYQ.Data 对于分布式缓存Redis、MemCache高可用的改进及性能测试

    背景: 随着.NET Core 在 Linux 下的热动,相信动不动就要分布式或集群的应用的需求,会慢慢火起来. 所以这段时间一直在研究和思考分布式集群的问题,同时也在思考把几个框架的思维相对提升到这 ...

  10. brew 安装指定版本命令行工具 tmux 多版本实现

    Homebrew 是 macOS 命令安装工具,其核心库里的命令行在 github homebrew-core 仓库上维护. 核心库命令大概有 5000 条左右,大部分的命令行工具只保留了最新版本的 ...