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. stm32学习笔记之GPIO功能框图分析

    GPIO 是通用输入输出端口的简称,简单来说就是STM32 可控制的引脚,STM32 芯片的GPIO 引脚与外部设备连接起来,从而实现与外部通讯.控制以及数据采集的功能.STM32 芯片的GPIO被分 ...

  2. sonar-project.propertie分析参数

    SonarScanner 是当您的构建系统没有特定扫描仪时使用的扫描仪. 配置您的项目 在你的项目根目录中创建一个名为的配置文件 sonar-project.properties # must be ...

  3. amba web

    arm amba doc https://developer.arm.com/docs

  4. jQuery常用验证

    1.文本框不能为为空 if ($("#RushStartTime").val() == "") { alert("请输入该产品.."); $ ...

  5. wpa_supplicant启动出错rfkill: Cannot open RFKILL control device

    在板子是调试网络,千辛万苦把wpa_supplicant及其依赖都移植编译进来了,在板子上调试启动的时候启动报错了 D/wpa_supplicant( 1152): wpa_supplicant v2 ...

  6. 全志Tina_dolphin播放音视频裸流(h264,pcm)验证

    最近在验证tina对裸流音视频的支持,主要指h264视频裸流及pcm音频裸流. 在原始sdk中有针对很多video和audio类型的parser,但就是没有找到pcm和h264的parser,所以需要 ...

  7. JAVA笔记14__多线程共享数据(同步)/ 线程死锁 / 生产者与消费者应用案例 / 线程池

    /** * 多线程共享数据 * 线程同步:多个线程在同一个时间段只能有一个线程执行其指定代码,其他线程要等待此线程完成之后才可以继续执行. * 多线程共享数据的安全问题,使用同步解决. * 线程同步两 ...

  8. Vue面试题01

    说出vue常用的指令: v-text,  v-html,  v-bind,  v-for,  v-if,  v-else,  v-else-if,   v-show,    v-on, 谈谈你对MVC ...

  9. c++ 算法 next_permutation

    遇到这个算法是在大牛写的10行的8皇后问题中,下面首先给出这个10行就解决了8皇后的NB代码,我目前还是没有看懂对于皇后不在同一列的判断,因为他巧妙的用了移位操作. #include<iostr ...

  10. JMeter学习笔记--录制脚本(一)

    ---------------------------------------------------------------------------------------------------- ...