学习ArrayList的扩容机制
基于jdk8
1.首先我们看new ArrayList中
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
ArrayList底层就是一个Object数组;
这里DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个静态的空的Object数组,所以ArrayList初始容量实际是0;
2.add方法
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } private int size;
这里size默认值为0
private void ensureCapacityInternal(int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); } ensureExplicitCapacity(minCapacity); } private static final int DEFAULT_CAPACITY = 10;
默认DEFAULT_CAPACITY容量为10,但是这是在使用add方法时,ArrayList才会进行初始化容量赋值。
首次加载时,elementData 对象肯定是一个空的Object数组,所以minCapacity = 10;
3.接下来我们再看看ensureExplicitCapacity这个方法;
private void ensureExplicitCapacity(int minCapacity) { modCount++; // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); }
首次加载时minCapacity = 10,所以minCapacity - elementData.length肯定大于0,然后进行扩容判断
还有就是当数组大小超过原有容量之后会进行扩容。扩容大小为 old +(old/2) -->1.5倍
private void grow(int minCapacity) { // overflow-conscious code int 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 final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
初次加载,oldCapacity = 0,所以newCapacity=0;newCapacity - minCapacity <0,所以最后初始化加载时newCapacity 为10了。
最后 newCapacity 会与MAX_ARRAY_SIZE进行比较,不能超过Integer的最大值减8
The maximum size of array to allocate.
Some VMs reserve some header words in an array.
Attempts to allocate larger arrays may result in
OutOfMemoryError: Requested array size exceeds VM limit
vm虚拟机会在数组中存放一些数据,所以不能等于Integer.MAX_VALUE(2147483647)
private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE)? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
--拓展--
因为ArrayList底层是一个Object数组,在多线程环境中可以会出现并发争抢的问题,
java提供三种解决方案:
1.new Vector jdk1.0就出现的类
public void add(E e) { int i = cursor; synchronized (Vector.this) { checkForComodification(); Vector.this.add(i, e); expectedModCount = modCount; } cursor = i + 1; lastRet = -1; }
加了synchronized保证add方法线程安全性,但是并发性急剧下降,所以在jdk1.2中才
会出现ArrayList这个类。
2.Collections.SynchronizedList(new ArrayList());
public boolean add(E e) { synchronized (mutex) {return c.add(e);} }
3.new CopyOnWriteArrayList();
private transient volatile Object[] array;
使用volatile关键字,保证array数组可见性,禁止指令重排;
public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
add方法添加ReentrantLock 可重入锁(递归锁),保证add方法在多线程环境中程序执行
的安全性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2017-12-12 java生成二维码