「集合底层」Vector底层结构及源码剖析

news2024/11/24 12:44:22

「集合源码」Vector底层结构及源码剖析

文章目录

  • 「集合源码」Vector底层结构及源码剖析
    • 一、基本介绍
    • 二、类继承关系
    • 三、Vector特性
    • 四、底层源码分析
      • 1、四个构造器
      • 2. 添加一个元素的过程以及扩容机制
    • 五、Vector与ArrayList
      • 共同点
      • 区别

一、基本介绍

Vector 是一个矢量队列,它的继承关系和ArrayList是一样的,同样实现了RandomAccess标记接口,用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能Vector实现了Cloneable标记接口,用来指示Object.clone()方法可以合法地对该类实例按字段复制。如果在没有实现 Cloneable接口的实例上调用 Objectclone 方法,则会导致抛出 CloneNotSupportedException 异常。Serializable 接口: 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。


二、类继承关系

image-20221218160040558


三、Vector特性

  • 1、底层由一个可以增长的数组组成
  • 2、Vector 通过 capacity (容量) 和 capacityIncrement (增长数量) 来尽量少的占用空间
  • 3、扩容时默认扩大两倍
  • 4、最好在插入大量元素前增加 vector 容量,那样可以减少重新申请内存的次数
  • 5、通过 iteratorlastIterator 获得的迭代器是 fail-fast
  • 6、通过 elements 获得的老版迭代器 Enumeration 不是 fail-fast 的
  • 7、同步类,每个方法前都有同步锁 synchronized

四、底层源码分析

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;
}

<6> 回到add方法

// 将传递进来的元素添加到数组的末尾
elementData[elementCount++] = e;	

至此vector的一次add就完成了


五、Vector与ArrayList

共同点

  • 1、都是基于数组
  • 2、都支持随机访问
  • 3、默认容量都是 10
  • 4、都有扩容机制

区别

  • 1、Vector 出生的比较早,JDK 1.0 就出生了,ArrayList JDK 1.2 才出来
  • 2、VectorArrayList 多一种迭代器 Enumeration
  • 3、Vector 是线程安全的,ArrayList 不是线程安全的
  • 4、Vector 默认扩容2倍ArrayList1.5倍
  • 5、Vector相比ArrayList很多方法都使用了synchronized来保证线程安全,这也就意味着每次都需要获得对象同步锁,效率会明显比ArrayList要低。

参考

Java中的Vector源码解析

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/100303.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【开发指南】AR Foundation 扫描

开发平台&#xff1a;Unity 2020 版本以上 编程平台&#xff1a;Visual Studio 2022 面向平台&#xff1a;IOS 设备   一、本文聚焦问题点 使用哪种 API 完成相机权限的获取如何进行画面跟踪对象的捕获。 对深入了解AR的开发者尤为重要。但只是从应用目的上&#xff0c;只需要…

C++PrimerPlus 第八章 函数探幽-8.5 函数模板

目录 8.5 函数模板 8.5.1 重载的模板 8.5.2 模板的局限性 8.5.3 显式具体化 8.5.3.1 第三代具体化&#xff08;ISO/ANSI C标准&#xff09; 8.5.3.2 显式具体化示例 8.5.4 实例化和具体化 8.5.5 编译器选择使用哪个函数版本 8.5.5.1 完全匹配和最佳匹配 8.5.5.2 部分…

计算机毕设Python+Vue学生风采网(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【Python学习记录】numpy数组用法整理

✨ 博客主页&#xff1a;小小马车夫的主页 ✨ 所属专栏&#xff1a;Python学习记录 文章目录前言一、numpy数组创建1、numpy.array创建数组2、从已有数组中创建数组二、numpy创建数组初始化1、numpy.zero2、numpy.ones3、numpy.arange4、numpy.linspace5、numpy.random三、nump…

Mentor-dft 学习笔记 day44-Low-Power Design Test

Low-Power Testing Overview Tessent Scan支持启用低功耗测试的操作。 •在存在孤立cell的情况下插入专用包装cell。 •根据驱动的逻辑和电源域的优先级将专用包装单元分配给电源域。 低功耗设计流程包括以下步骤&#xff1a; 1.在CPF/UPF文件中指定低功耗数据规范。 2.在设计…

[附源码]计算机毕业设计Python的校园报修平台(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

RequestResponse

Request Request继承体系 Request获取请求数据 获取请求数据 通用方式获取请求参数 WebServlet("/req1") public class req1 extends HttpServlet {Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOE…

电脑怎么隐藏文件夹?6个步骤完成!

在日常办公使用电脑的过程中&#xff0c;总会出现各种问题。比如&#xff1a;电脑怎么隐藏文件夹&#xff1f;当我们需要这些数据时&#xff0c;我们又该如何恢复&#xff1f;为了解决这些问题&#xff0c;小编在这里总结了6个操作步骤来隐藏文件夹数据的方法。让我们一起来看看…

【代码随想录】Day34链表:力扣203,707,206,142,面试0207

目录 基本知识 概念、类型、存储方式&#xff1a; 定义 操作 性能分析 经典方法 虚拟头结点 思路 例题&#xff1a;力扣203 链表的基本操作 思路 例题&#xff1a;力扣707 反转链表 思路 例题&#xff1a;力扣206 删除倒数第N个结点 思路&#xff1a; 例题&am…

jsp+ssm计算机毕业设计-东湖社区志愿者管理平台【附源码】

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JSPSSM mybatis Maven等等组成&#xff0c;B/S模式 Mave…

[附源码]计算机毕业设计Python的在线作业批改系统(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

tomcat 服务突然停止、日志排查以及解决方案

文章目录一、服务停止调研1. jvm排查2. 日志排查3. 推测与ssh会话有关二、ssh会话强制退出验证2.1. 手动强制关闭进程12.2. 手动强制关闭进程22.3. 总结归纳与解决方案一、服务停止调研 1. jvm排查 有可能是jvm配置参数导致的&#xff0c;然后在/var/log和/app/apache-tomcat…

2022 软件测试大题【太原理工大学】

大题应该是有两道&#xff0c;每道10分&#xff0c;具体是不是我也不知道&#xff0c;老师也不确定。① 白盒测试 —— 控制流图&#xff0c;给出一段代码&#xff0c;画出控制流图&#xff0c;根据公式求程序段的环形复杂度&#xff0c;求程序基本路径集合中的独立路径&#x…

永磁同步电机(PMSM)磁场定向控制(FOC)电流环PI调节器参数整定

文章目录前言一、调节器的工程设计方法二、电流环PI调节器的参数整定2.1.电流环的结构框图2.2.典型I型系统2.3.电流环PI参数整定计算公式三、电流环PI调节器设计实例3.1.永磁同步电机磁场定向的电流闭环控制3.2.电流环PI参数计算3.3.仿真分析总结前言 本章节采用工程设计的方法…

CommaFeed:仿Google Readerd的RSS阅读器

最近老苏身边中招的人也开始多起来了&#xff0c;大家要保重~ 本文开始于 9 月下旬&#xff0c;完成于 10 月下旬&#xff0c;目前正式版本还是老苏打包时用的 2.6.0&#xff0c;不过现在已经有了 3.0.0 RC1 什么是 CommaFeed &#xff1f; CommaFeed 是受 Google Reader 启发而…

CS144-Lab0解析

讲在开头 cs144建议我们使用Modern C来完成所有的lab&#xff0c;关于modern c的全面的用法可以在(http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines)获取。 以下是一些代码规范&#xff1a; 不要使用malloc()和free()不要使用new和delete在不得不使用指针时应…

如何自动估算项目开发成本及报价,提高估算效率?

项目估算需要有科学专业的估算方法&#xff0c;需要有明确的量化指标&#xff0c;那么如何自动估算项目开发成本及报价&#xff1f; 第一步&#xff1a;功能点复杂程度的估算 CoCode需求分析工具&#xff0c;根据用户需求&#xff0c;使用COSMIC和IFPUG项目规模估算法&#xff…

数据结构C语言版 —— 队列+循环队列实现

文章目录队列1.概念2. 生活中队列应用3. 队列的实现初始化队列入队列出队列获取队头元素获取队尾元素获取队列中元素个数判断队列是否为空销毁队列2. 循环队列队列 1.概念 和栈相反&#xff0c;队列(queue)是一种先进先出的线性表&#xff0c;它只允许在一端进行插入&#xf…

C#-winform调用COM组件(COM组件由Qt开发)

一、场景介绍 在项目开发中,需要Qt与C#进行混合编程,完成项目开发。C#这边作为主框架,Qt负责编写插件,将功能模块通过COM组件的形式封装注册,再由C#调用、交互完成最终的项目。 程序开发环境: win10 64位 编译器: VS2017 Qt版本: Qt5.12.6 二、Qt封装COM组件 2.1 环境…

android flutter 安装

下载 flutter官网下载安装&#xff1a;https://flutter.dev/docs/development/tools/sdk/releases 将下载下来的zip安装包解压到想安装Flutter SDK的路径。注意&#xff0c;不要将flutter安装到需要一些高权限的路径&#xff0c;比如C:\Program Files\ 配置环境变量 添加fl…