当前位置: 首页 > news >正文

ArrayList源码解读

参数

	//默认初始容量private static final int DEFAULT_CAPACITY = 10;//空数组(用于空实例)private static final Object[] EMPTY_ELEMENTDATA = {};//用于默认大小空实例的共享空数组private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//保存数据的数组transient Object[] elementData; // non-private to simplify nested class access//元素个数private int size;

注意:这里有两个空数组,第一个空数组是容量为0的时候的数组,第二个空数组是使用空参构造器的时候的数组

构造方法

	//带有参数的构造器public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);}}//这就是与上面不一样的地方public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}public ArrayList(Collection<? extends E> c) {Object[] a = c.toArray();if ((size = a.length) != 0) {if (c.getClass() == ArrayList.class) {elementData = a;} else {elementData = Arrays.copyOf(a, size, Object[].class);}} else {// replace with empty array.elementData = EMPTY_ELEMENTDATA;}}

扩容方法

如果有必要增加此ArrayList实例的容量以确保它至少能容纳元素的数量

	public void ensureCapacity(int minCapacity) {//这里就开始判处出前面两个空数组的区别了//如果这个list是无参构造的化没那么minExpand就为10,否则为0int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)? : DEFAULT_CAPACITY;//如果最小容量大于已有的最大容量if (minCapacity > minExpand) {ensureExplicitCapacity(minCapacity);}}

如果最小所需容量大于了实际可存储容量那么就需要扩容

判断是否真的需要扩容

   private void ensureExplicitCapacity(int minCapacity) {modCount++;if (minCapacity - elementData.length > 0)grow(minCapacity);}

这里就是扩容的具体办法其中分为几个情况

最开始新容量等于旧容量的1.5倍

  1. 新容量大等于最小所需容量,那么最后的新容量就等于旧容量的1.5倍

  2. 新容量小于最小所需容量,那么最后的新容量就等于最小所需容量

  3. 新容量大于List中规定最大容量,判断最小所需容量是否大于了List中规定的最小容量,如果没有则新容量还是等于最小容量,如果大于了则新容量等于Integer的最大值

  private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length;int newCapacity = oldCapacity + (oldCapacity >> 1);if (newCapacity - minCapacity < 0)newCapacity = minCapacity;if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);}private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}
 	private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));}

计算最小容量是否会等于10

    private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;}

增删改查方法

增删改查的方法都是十分简单的所以不过多赘述

但是要注意在增加和删除方法的每一次调用的时候都会使modCount++

Iterator迭代器

在ArrayList内部有个Itr的内部类

private class Itr implements Iterator<E> {//当前游标位置int cursor; //上一个游标位置int lastRet = -1; //修改次数int expectedModCount = modCount;Itr() {}//是否还存在下一个public boolean hasNext() {return cursor != size;}@SuppressWarnings("unchecked")public E next() {//检查期待修改次数与实际的修改次数是否发生变化//如果有变化就抛出异常checkForComodification();int i = cursor;if (i >= size) //判断是否越界throw new NoSuchElementException();Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length) //判断是否越界throw new ConcurrentModificationException();cursor = i + 1; //游标变为下一个return (E) elementData[lastRet = i];}public void remove() {if (lastRet < 0)throw new IllegalStateException();checkForComodification();try {ArrayList.this.remove(lastRet);cursor = lastRet;lastRet = -1;expectedModCount = modCount;} catch (IndexOutOfBoundsException ex) {throw new ConcurrentModificationException();}}@Override@SuppressWarnings("unchecked")public void forEachRemaining(Consumer<? super E> consumer) {Objects.requireNonNull(consumer);final int size = ArrayList.this.size;int i = cursor;if (i >= size) {return;}final Object[] elementData = ArrayList.this.elementData;if (i >= elementData.length) {throw new ConcurrentModificationException();}while (i != size && modCount == expectedModCount) {consumer.accept((E) elementData[i++]);}// update once at end of iteration to reduce heap write trafficcursor = i;lastRet = i - 1;checkForComodification();}final void checkForComodification() {if (modCount != expectedModCount)throw new ConcurrentModificationException();}}

快速失败

前面都说了modCount属性,然后迭代器哪里也使用到了所以这里就说一下它的作用,它的作用就是实现快速失败,每次迭代器遍历的时候都会去查询实际的modCount属性与迭代器中保存的modCount属性是否相同,如果不同那么就抛出异常,这就是快速失败

拓展:安全失败:安全失败使用的写时复制技术,这个迭代器中遍历的数据是复制的数据,所以对于原有数据的修改不会影响到复制的数据

http://www.lryc.cn/news/23140.html

相关文章:

  • python实战应用讲解-【语法高级篇】时间与日期(附python示例代码)
  • D. Moscow Gorillas(双指针 + 区间分析)
  • 华为OD机试题,用 Java 解【相同数字的积木游戏 1】问题
  • Python实现GWO智能灰狼优化算法优化BP神经网络分类模型(BP神经网络分类算法)项目实战
  • 无线蓝牙耳机哪个牌子好?2023质量好的无线蓝牙耳机推荐
  • Qt之QTableView自定义排序/过滤(QSortFilterProxyModel实现,含源码+注释)
  • 电商(强一致性系统)的场景设计
  • 算法与数据结构(一)
  • 【Python】元组如何创建?
  • qt操作文件以及字符串转换
  • 数组中只出现一次的两个数字(异或法思路)
  • python支持的操作系统有哪些
  • S3C2440开发环境搭建
  • 软件测试之测试用例
  • null和undefined的区别有哪些?
  • 【强烈建议收藏:计算机网络面试专题:HTTP协议、HTTP请求报文和响应报文、HTTP请求报文常用字段、HTTP请求方法、HTTP响应码】
  • 关于Java中的静态块讲解
  • ledcode【用队列实现栈】
  • 【基础算法】双指针----字符串删减
  • Billu靶场黑盒盲打——思路和详解
  • 【2363. 合并相似的物品】
  • 【C++提高编程】C++全栈体系(二十四)
  • c++11 标准模板(STL)(std::unordered_set)(十一)
  • AI/CV大厂笔试LeetCode高频考题之基础核心知识点
  • 华为OD机试题,用 Java 解【静态扫描最优成本】问题
  • 常见无线技术方案介绍
  • 收获满满的2022年
  • react的生命周期
  • scanpy 单细胞分析API接口使用案例
  • 【Vue3 第二十一章】Teleport组件传送