导读:本期聚焦于小伙伴创作的《Java ArrayDeque 的真实容量是多少?揭秘文档与源码中的容量规则》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Java ArrayDeque 的真实容量是多少?揭秘文档与源码中的容量规则》有用,将其分享出去将是对创作者最好的鼓励。

ArrayDeque是Java中基于数组实现的双端队列,很多开发者在使用时会发现它的容量表现和普通的ArrayList存在差异,甚至和官方文档的描述存在容易混淆的地方。要搞清楚它的真实容量,需要结合文档说明和底层源码一起分析。

Java ArrayDeque 的真实容量是多少?揭秘文档与源码中的容量规则

ArrayDeque的官方文档容量说明

根据Java官方文档的描述,ArrayDeque的底层是一个可动态扩容的数组,默认的初始容量是16,并且这个容量会保证是2的幂次方。文档中提到,ArrayDeque会按需扩容,不会出现容量不足的情况,但并没有明确说明扩容后的具体容量计算规则,也没有说明容量和实际可存储元素数量的关系。

从源码看初始容量逻辑

我们先看ArrayDeque的构造方法相关源码,理解初始容量的计算规则:

// 默认无参构造,初始容量为16
public ArrayDeque() {
    elements = new Object[16];
}

// 指定初始容量的构造方法
public ArrayDeque(int numElements) {
    allocateElements(numElements);
}

// 分配元素的核心方法
private void allocateElements(int numElements) {
    int initialCapacity = 8;
    // 找到大于等于numElements的最小2的幂次方,且不小于8
    if (numElements >= initialCapacity) {
        initialCapacity = numElements;
        initialCapacity |= (initialCapacity >>> 1);
        initialCapacity |= (initialCapacity >>> 2);
        initialCapacity |= (initialCapacity >>> 4);
        initialCapacity |= (initialCapacity >>> 8);
        initialCapacity |= (initialCapacity >>> 16);
        initialCapacity++;
        // 处理溢出情况,如果超过int最大值,回退到2的30次方
        if (initialCapacity < 0) {
            initialCapacity >>>= 1;
        }
    }
    elements = new Object[initialCapacity];
}

从源码可以看到,当使用指定初始容量的构造方法时,ArrayDeque不会直接使用传入的参数作为数组长度,而是会计算大于等于该参数的最小2的幂次方,且最小不会小于8。比如传入10,最终数组长度会是16;传入20,最终数组长度会是32。

真实容量与可存储元素数量的关系

很多开发者会误以为数组的长度就是ArrayDeque的真实容量,也就是最多能存储的元素数量,但实际上ArrayDeque为了保证双端队列的高效操作,会预留一个数组位置不使用。我们可以通过扩容的源码来验证这一点:

// 扩容方法,当元素数量达到数组长度-1时触发
private void doubleCapacity() {
    int p = head;
    int n = elements.length;
    int r = n - p;
    int newCapacity = n << 1;
    if (newCapacity < 0) {
        throw new IllegalStateException("Sorry, deque too big");
    }
    Object[] a = new Object[newCapacity];
    System.arraycopy(elements, p, a, 0, r);
    System.arraycopy(elements, 0, a, r, p);
    elements = a;
    head = 0;
    tail = n;
}

在ArrayDeque中,tail指针指向的是下一个可插入元素的位置,当tail == head且数组不是空的时候,就说明队列已满,此时会触发扩容。而初始状态下head和tail都为0,当插入第一个元素后tail变为1,所以当数组长度为n时,最多只能存储n-1个元素,这就是它的真实可存储容量。

不同场景下的容量验证

我们可以通过简单的测试代码验证上述结论:

import java.util.ArrayDeque;

public class ArrayDequeTest {
    public static void main(String[] args) {
        // 测试默认构造的容量
        ArrayDeque<Integer> deque1 = new ArrayDeque<>();
        // 反射获取底层数组长度
        java.lang.reflect.Field elementsField = ArrayDeque.class.getDeclaredField("elements");
        elementsField.setAccessible(true);
        Object[] elements1 = (Object[]) elementsField.get(deque1);
        System.out.println("默认构造底层数组长度:" + elements1.length); // 输出16

        // 测试指定容量为10的情况
        ArrayDeque<Integer> deque2 = new ArrayDeque<>(10);
        Object[] elements2 = (Object[]) elementsField.get(deque2);
        System.out.println("指定容量10的底层数组长度:" + elements2.length); // 输出16

        // 测试可存储元素数量
        ArrayDeque<Integer> deque3 = new ArrayDeque<>(8);
        Object[] elements3 = (Object[]) elementsField.get(deque3);
        System.out.println("指定容量8的底层数组长度:" + elements3.length); // 输出8
        // 尝试插入8个元素
        for (int i = 0; i < 8; i++) {
            deque3.add(i);
        }
        System.out.println("插入8个元素后是否触发扩容:" + (deque3.size() == 8)); // 输出false,实际插入7个就会满
    }
}

总结

ArrayDeque的真实容量需要从两个维度理解:底层数组的长度始终是2的幂次方,最小为8;而实际可存储的元素数量是底层数组长度减1。文档中提到的容量更多是指底层数组的长度,而开发者在使用时更关注的是可存储元素的数量,需要明确两者的差异。在开发中如果需要预估ArrayDeque的容量,建议按照需要存储的元素数量加1后取最近的2的幂次方来指定初始容量,避免不必要的扩容操作。

ArrayDequeJava集合双端队列容量扩容修改时间:2026-07-16 13:54:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。