Vector总结及部分底层源码分析
Vector总结及部分底层源码分析
1. Vector继承的抽象类和实现的接口
- Vector类实现的接口
- List接口:里面定义了List集合的基本接口,Vector进行了实现
- RandomAccess接口
- Cloneable接口
- Serializable:标记该类支持序列化
- Vector继承了AbstractList抽象类
2. Vector底层的数据结构
Vector底层是基于数组实现的
特点:
- 数组在内存中是一个内存地址连续的,使用存储的元素也有序的,固定内存大小的内存空间,并且Vector可以存放重复的元素。允许存储 一个null或者多个null。
优点:
- 因为Vector在可能发送线程安全的方法上都添加了 synchronized 关键字进行了同步设置,所以Vector是线程安全的集合,在多线程的情况下可以直接使用。
- 因为使用了同步锁的原因在查询效率上不如ArrayList快,但是相比于链表而言查询效率还是快。
缺点:
- 当向Vector集合中存储的新的元素时,长度已经不够时,就会触发Vector底层的扩容机制。其实底层就是数组扩容。因为数组扩容需要把旧的数组元素复制到新的数组中,所以在数据量特别大的时候,扩容的效率不高
- 在指定位置添加和修改元素效率不高(尾部除外)。
- 例如:在数组的尾部以外的地方插入一个元素,那么为例保证整个数组中所有元素的连续存储性,就必须向将从该位置到尾部的所有元素进行后移一位,腾出一个空的位置,再把新的元素进行插入。删除也是,删除了指定位置的之后需要把从该元素到尾部的所有元素向前移动一个位置。
- 虽然使用了 synchronized 保证线程安全,但是会损失掉一部分性能,所以目前已经基本弃用该集合。
3. Vector适用的场景
- 在多线程情况下,频繁对数据进行查找与修改的场景
- 但是为例将性能进行提升,可以创建线程安全ArrayList进行代替,使用Vector集合做的事情,使用ArrayList都可以做到,所以Vector基本已经不使用。
// 创建多线程环境下,线程安全的ArrayList集合,使用Collections集合工具类中的 synchronizedList() 方法
List<Object> list=Collections.synchronizedList(new ArrayList<Object>());
4. Vector底层源码分析
1. 四个构造函数
1. 无参构造函数
/**
* 默认无参构造函数
*/
public Vector() {
// 调用只有一个参数的构造函数,给参数一个定值10
this(10);
}
2. 有一个参数的构造函数
/**
* 有一个参数的构造函数
* @param initialCapacity 创建对象时如果使用默认的无参构造函数,默认大小为10
*/
public Vector(int initialCapacity) {
// 调用有两个参数的构造函数
this(initialCapacity, 0);
}
3. 有两个参数的构造函数
/**
* 有两个参数的构造函数,第一个参数代表数组的初始化长度,第二个是数组需要进行扩容的的增量值
* @param initialCapacity 集合的初始化长度大小,如果创建集合时采用无参构造器,则默认为10
* @param capacityIncrement Vector需要自动扩容时增加的容量值,不传递时默认为0
* @throws IllegalArgumentException 发生异常时抛出异常
*/
public Vector(int initialCapacity, int capacityIncrement) {
// 调用父类的构造函数
super();
// 判断传递进来的默认初始化集合长度大小的值是否小于0,如果小于则抛出异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity);
// 创建一个Object类型的数组,长度为传递进来的 initialCapacity ,用 elementData 接收
this.elementData = new Object[initialCapacity];
// Vector需要自动扩容时增加的容量值,不传递时默认为0,在后面的扩容方法中会体现出来
this.capacityIncrement = capacityIncrement;
}
- 变量说明:
// 存放集合的元素值,类型Object类型,可以存储任意类型的数据
protected Object[] elementData;
// 数组需要进行扩容的的增量值,只有在调用有两个参数的构造函数是才可以改变其大小
// 如果采用其他两个构造函数创建集合,则默认是0
protected int capacityIncrement;
- Vector父类的构造函数
/**
* Vector父类的构造函数,不做任何事情
*/
protected AbstractList() {}
4. 有参构造(传入一个Collection类型的集合)
/**
* 在初始化的时候直接将一个集合传入,可以把传入集合的元素全部复制到创建的新集合中
* @param c 传入的集合
* @throws NullPointerException 当传入的集合为空时,会抛出异常
*/
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
2. 添加一个元素的过程以及扩容机制
1. 调用对应类型的装箱方法
在每次添加数据时,如果数据是基本数据类型,会先将基本数据类型进行装箱操作,把基本数据类型转换成对应的包装类型(引用数据类型)
// 例如:集合中存放Integer数据类型,在进行add操作时,会先进行装箱操作
/**
* 将基本数据类转换为引用数据类型
* @param i 传入的参数为一个基本型数据类型
* @return 返回的参数是一个基本数据类型的包装类(引用数据类型)
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
2. 调用 add() 方法
/**
* 添加元素方法,成功返回true,失败会抛出异常
* @param e 需要进行添加的元素值
* @return <tt>true</tt> 添加成功返回true,添加过程中如果失败会抛出异常
*/
public synchronized boolean add(E e) {
// 记录集合被修改的次数
modCount++;
// 判断是否需要扩容
ensureCapacityHelper(elementCount + 1);
// 将传递进来的元素添加到数组的末尾
elementData[elementCount++] = e;
return true;
}
- 变量说明:
// 记录集合被修改的次数
protected transient int modCount = 0;
// 记录当前的vector集合中存储的实际元素个数
protected int elementCount;
3. 判断是否需要扩容 ensureCapacityHelper()
/**
* 按照传递进来的具体值,判断是否需要进行扩容操作
* @param minCapacity 在原来集合实际元素个数的数目上加1,代表添加元素之后数组的实际长度
*/
private void ensureCapacityHelper(int minCapacity) {
// 当实际需要的数组长度 - 数组实际的长度大于0时,表示需要进行扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity); // 扩容的核心方法
}
4. 核心扩容方法 grow()
/**
* 具体的扩容方法
* @param minCapacity 经过判断之后存储数据的数组需要的容量大小
*/
private void grow(int minCapacity) {
// 获取未扩容之前的数组长度
int oldCapacity = elementData.length;
// 判断 capacityIncrement 增量值是否大于0,如果大于0每次扩容大小是增量值,否则按原来长度的2倍扩容
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
// 当扩容之后的长度小于实际需要的长度时,将实际需要的长度作为扩容之后的长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 当扩容之后的长度大于限定的最大长度时
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 使用数组的 copyOf 对数组进行扩容
elementData = Arrays.copyOf(elementData, newCapacity);
}
- 变量说明:
// 整数类型的最大值减8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
5. 当数组要求的扩容的长度超过限定的最大值时
/**
* 具体的扩容方法
* @param minCapacity 经过判断之后存储数据的数组需要的容量大小
*/
private static int hugeCapacity(int minCapacity) {
// 判断是否是内存溢出
if (minCapacity < 0)
throw new OutOfMemoryError();
// 判断实际需要的数组长度是否大于设置的最大值,是则返回整数类型的最大值,否则返回设置的最大值
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
Vector总结及部分底层源码分析的更多相关文章
- List-LinkedList、set集合基础增强底层源码分析
List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...
- List-ArrayList集合基础增强底层源码分析
List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...
- LInkedList总结及部分底层源码分析
LInkedList总结及部分底层源码分析 1. LinkedList的实现与继承关系 继承:AbstractSequentialList 抽象类 实现:List 接口 实现:Deque 接口 实现: ...
- JAVA ArrayList集合底层源码分析
目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...
- 分布式缓存技术之Redis_Redis集群连接及底层源码分析
目录 1. Jedis 单点连接 2. Jedis 基于sentinel连接 基本使用 源码分析 本次源码分析基于: jedis-3.0.1 1. Jedis 单点连接 当是单点服务时,Java ...
- Servlet和Tomcat底层源码分析
Servlet 源码分析 Servlet 结构图 Servlet 和 ServletConfig 都是顶层接口,而 GenericServlet 实现了这两个顶层接口,然后HttpServlet ...
- 持久层Mybatis3底层源码分析,原理解析
Mybatis-持久层的框架,功能是非常强大的,对于移动互联网的高并发 和 高性能是非常有利的,相对于Hibernate全自动的ORM框架,Mybatis简单,易于学习,sql编写在xml文件中,和代 ...
- Java——HashMap底层源码分析
1.简介 HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap 最多只允许一条记录的key为 nu ...
- Java——ArrayList底层源码分析
1.简介 ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔, 当数组大小不满足时需要增加存储能力,就要将已经有数 ...
随机推荐
- [LGP1866]编号
传送门 题意:找n个数,使得 $ 1 \leq a_i \leq Maxnumber_i $ 求有多少种组合 这题我们可以看到,还有一种无解的情况 我们可以先判断无解的情况 首先把Maxnumber数 ...
- Python 检查当前运行的python版本 python2 python3
检查当前运行的python版本,可以帮助程序选择运行python2还是python3的代码 import sys if sys.version > '3': PY3 = True else: P ...
- ICPC Mid-Central USA Region 2019 题解
队友牛逼!带我超神!蒟蒻的我还是一点一点的整理题吧... Dragon Ball I 这个题算是比较裸的题目吧....学过图论的大概都知道应该怎么做.题目要求找到七个龙珠的最小距离.很明显就是7个龙珠 ...
- ansible安装和批量执行命令
yum install -y ansible 编辑 /etc/ansible/hosts 文件 # This is the default ansible 'hosts' file.## It sho ...
- [命令行]Mysql 导入 excel 文件
将 excel 表格中的数据批量导入数据库中 将要导入的表删除字段名,只留下要导入的数据. 将文件另存为 *.csv格式,可以用记事本打开(实际上就是标准的逗号分隔的数据 进入mysql,输入命令,打 ...
- 从0到1使用Kubernetes系列(六):数据持久化实战
本文是从 0 到 1 使用 Kubernetes 系列第六篇,上一篇<从 0 到 1 使用 Kubernetes 系列(五):Kubernetes Scheduling>介绍了 Kuber ...
- 有关于ONVIF
1.什么是ONVIF2008年5月,由安讯士(AXIS)联合博世(BOSCH)及索尼(SONY)公司三方宣布携手共同成立一个国际开放型网络视频产品标准网络接口开发论坛,取名为ONVIF(Open Ne ...
- SpringCould | Nacos与Feign
服务注册Nacos 介绍 概念 一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台. Nacos: Dynamic Naming and Configuration Service Nac ...
- redis数据存储的细节
redis是一个K-V NoSql非关系型数据库,redis有物种数据类型,分别是String,Hash,list,set,zset:这五种类型都是针对K-V中的V设计的. 1.总体介绍:关于redi ...
- go输入Hello word
package main import "fmt" func main() { fmt.Println("hello word") } 输入hello ...