Vector总结及部分底层源码分析

1. Vector继承的抽象类和实现的接口

  • Vector类实现的接口

    1. List接口:里面定义了List集合的基本接口,Vector进行了实现
    2. RandomAccess接口
    3. Cloneable接口
    4. Serializable:标记该类支持序列化
  • Vector继承了AbstractList抽象类

2. Vector底层的数据结构

  • Vector底层是基于数组实现的

    1. 特点:

      1. 数组在内存中是一个内存地址连续的,使用存储的元素也有序的,固定内存大小的内存空间,并且Vector可以存放重复的元素。允许存储 一个null或者多个null。
    2. 优点:

      1. 因为Vector在可能发送线程安全的方法上都添加了 synchronized 关键字进行了同步设置,所以Vector是线程安全的集合,在多线程的情况下可以直接使用。
      2. 因为使用了同步锁的原因在查询效率上不如ArrayList快,但是相比于链表而言查询效率还是快。
    3. 缺点:

      1. 当向Vector集合中存储的新的元素时,长度已经不够时,就会触发Vector底层的扩容机制。其实底层就是数组扩容。因为数组扩容需要把旧的数组元素复制到新的数组中,所以在数据量特别大的时候,扩容的效率不高
      2. 在指定位置添加和修改元素效率不高(尾部除外)。
        • 例如:在数组的尾部以外的地方插入一个元素,那么为例保证整个数组中所有元素的连续存储性,就必须向将从该位置到尾部的所有元素进行后移一位,腾出一个空的位置,再把新的元素进行插入。删除也是,删除了指定位置的之后需要把从该元素到尾部的所有元素向前移动一个位置。
      3. 虽然使用了 synchronized 保证线程安全,但是会损失掉一部分性能,所以目前已经基本弃用该集合。

3. Vector适用的场景

  1. 在多线程情况下,频繁对数据进行查找与修改的场景
  2. 但是为例将性能进行提升,可以创建线程安全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总结及部分底层源码分析的更多相关文章

  1. List-LinkedList、set集合基础增强底层源码分析

    List-LinkedList 作者 : Stanley 罗昊 [转载请注明出处和署名,谢谢!] 继上一章继续讲解,上章内容: List-ArreyLlist集合基础增强底层源码分析:https:// ...

  2. List-ArrayList集合基础增强底层源码分析

    List集合基础增强底层源码分析 作者:Stanley 罗昊 [转载请注明出处和署名,谢谢!] 集合分为三个系列,分别为:List.set.map List系列 特点:元素有序可重复 有序指的是元素的 ...

  3. LInkedList总结及部分底层源码分析

    LInkedList总结及部分底层源码分析 1. LinkedList的实现与继承关系 继承:AbstractSequentialList 抽象类 实现:List 接口 实现:Deque 接口 实现: ...

  4. JAVA ArrayList集合底层源码分析

    目录 ArrayList集合 一.ArrayList的注意事项 二. ArrayList 的底层操作机制源码分析(重点,难点.) 1.JDK8.0 2.JDK11.0 ArrayList集合 一.Ar ...

  5. 分布式缓存技术之Redis_Redis集群连接及底层源码分析

    目录 1. Jedis 单点连接 2. Jedis 基于sentinel连接 基本使用 源码分析 本次源码分析基于: jedis-3.0.1 1. Jedis 单点连接   当是单点服务时,Java ...

  6. Servlet和Tomcat底层源码分析

    Servlet 源码分析   Servlet 结构图 Servlet 和 ServletConfig 都是顶层接口,而 GenericServlet 实现了这两个顶层接口,然后HttpServlet ...

  7. 持久层Mybatis3底层源码分析,原理解析

    Mybatis-持久层的框架,功能是非常强大的,对于移动互联网的高并发 和 高性能是非常有利的,相对于Hibernate全自动的ORM框架,Mybatis简单,易于学习,sql编写在xml文件中,和代 ...

  8. Java——HashMap底层源码分析

    1.简介 HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的. HashMap 最多只允许一条记录的key为 nu ...

  9. Java——ArrayList底层源码分析

    1.简介 ArrayList 是最常用的 List 实现类,内部是通过数组实现的,它允许对元素进行快速随机访问.数组的缺点是每个元素之间不能有间隔, 当数组大小不满足时需要增加存储能力,就要将已经有数 ...

随机推荐

  1. ESD

    Reverse standoff voltage是保护二极管的反向工作电压, 在这个电压, 二极管是不工作的. Breakdown voltage 是二极管的击穿电压, 超过这个电压后, 二极管迅速反 ...

  2. [CSP-S2021] 括号序列

    链接: P7914 题意: 有一堆规则,然后判断给定字符串有多少种填法符合规则. 分析: 一眼区间dp,状态数 \(n^2\),我们来分析这些规则. 把这些规则分成三类,第一类可以预处理出区间是否能表 ...

  3. Luogu P1118 [USACO06FEB]数字三角形 Backward Digit Sums | 搜索、数学

    题目链接 思路:设一开始的n个数为a1.a2.a3...an,一步一步合并就可以用a1..an表示出最后剩下来的数,不难发现其中a1..an的系数恰好就是第n层杨辉三角中的数.所以我们可以先处理出第n ...

  4. cf20B Equation(认真仔细题)

    题意: 求AX^2+BX+C=0的根 思路: 考虑到A,B,C所有可能的情况 代码: double a,b,c; int main(){ cin>>a>>b>>c; ...

  5. hdu 3032 Nim or not Nim? (SG,然后找规律)

    题意: n堆石头,每堆石头个数:s[1]...s[n]. 每人每次可以选择在一堆中取若干个(不能不取),或者把一堆石头分成两堆(两堆要都有石头). 无法操作者负. 数据范围: (1 ≤ N ≤ 10^ ...

  6. 微服务(七)Gateway服务网关

    1 为什么要有网关 权限控制:网关作为微服务入口,需要校验用户是是否有请求资格,如果没有则进行拦截. 路由和负载均衡:一切请求都必须先经过gateway,但网关不处理业务,而是根据某种规则,把请求转发 ...

  7. Oracle 扩容表空间

    system用户登陆oracle https://blog.csdn.net/zyingpei/article/details/88870693 首先查看表空间对应的数据文件位置以及大小 select ...

  8. ReplacingMergeTree:实现Clickhouse数据更新

    摘要:Clickhouse作为一个OLAP数据库,它对事务的支持非常有限.本文主要介绍通过ReplacingMergeTree来实现Clickhouse数据的更新.删除. 本文分享自华为云社区< ...

  9. JMeter学习记录收藏

    1.如何进行一个简单的性能测试 2.JMeter各种功能名词解释,比较全 3.聚合报告分析 4.CSV文件参数化,名词解释 5.JMeter快捷键

  10. .NET 开源工作流: Slickflow流程引擎高级开发(九) -- 条件事件模式解释及应用

    前言:在流程流转过程中,有时候需要条件模式的支持,这样可以使得流程流转更加灵活多变.比如在业务变量满足一定的条件时,可以启动特定配置的流程(或者位于主流程内部的子流程).本文主要描述条件启动和条件中间 ...