Java中的List集合无法初始化size?size和容量的区别是什么?

Java中的List集合无法初始化容量


我们都知道Java的List集合是有进行一个懒加载的优化的,当你没有在集合里面存放元素的时候,集合的size为0

可我记得List集合是可以指定大小的,于是我写了一段代码去进行测试

我这个时候就非常疑惑,我不是指定了大小吗?为什么size还是0?

想不明白,我就开始翻源码看看

原来size是记录的集合里面的元素个数,而不是集合的容量大小

  • 先看空参构造器

    从这段代码我们可以看得出懒加载机制,当没有往集合中放任何东西 的时候,就会初始化一个{}

java 复制代码
		private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
		transient Object[] elementData;
		public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
  • 再看看add()源码
java 复制代码
		public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 添加到集合之前先把判断一下当前容量size + 1是否会超出容量大小
        elementData[size++] = e;
        return true;
    }

		private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

		private static final int DEFAULT_CAPACITY = 10;

		private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
          	// 这里开始判断了,如果说你是第一次初始化,即集合为{}的话,我就会给你分配 DEFAULT_CAPACITY = 10
          	// 需要注意的是这里并没有把 size的值设置为10,size只记录集合里面有多少元素,而不是集合容量
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity; // 如果说你不是第一次添加了,就返回当前的容量 + 1的值
        // 这个地方有点绕,需要看传参 add方法里面的 ensureCapacityInternal(size + 1) 这个size + 1 就是minCapacity
    }

		private void ensureExplicitCapacity(int minCapacity) {
        modCount++; // 这里的modCount先不用管,因为ArrayList线程不安全,当modCount和expectModCount不一致就会抛异常

        // 当这个minCapacity大于数组长度的时候,也就意味着数组放不下了,这个时候就需要扩容了
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

		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);
        // 从源码我们可以看出,ArrayList集合底层的扩容机制就是通过数组的复制
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
  • 说点题外话,ArrayList集合是如何扩容的,拆分一下grow源码
java 复制代码
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);

这里可以看到newCapacity会把你原来集合的大小加上你原来集合大小的一半来进行扩容,就是1.5倍扩容,这是第一次

第二次扩容是什么时候呢?

java 复制代码
 if (newCapacity - minCapacity < 0)
     newCapacity = minCapacity;

当第一次扩容结束后,发现还是放不下,就会按照你给的集合大小来扩容了

当发现扩容后的大小超出了 MAX_ARRAY_SIZE 就会把整数的最大值给你了 Integer.MAX_VALUE

java 复制代码
		private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

 		if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
     
		private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
    }

总结


经过这次奇怪的尝试,终于搞清楚了size到底是什么了

我如果想要初始化List集合,就不能初始化集合容量 ,而是初始化集合的size

也就是说,如果想要真正的初始化这个size,就必须要往集合里面添加元素才能改变这个size属性

相关推荐
松仔log42 分钟前
JetPack——Paging3+Room
android·java·zoom
㳺三才人子6 小时前
初探 Flask
后端·python·flask·html
星栈独行6 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Lei活在当下6 小时前
先用起来,再理解,关于协程Coroutine应该知道的事
android·java·jvm
Java爱好狂.6 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易7 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
tongluowan0077 小时前
以ReentrantLock为例解释AQS的工作流程
java·模板方法模式·aqs·reentrantlock
装不满的克莱因瓶7 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl8 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
身如柳絮随风扬8 小时前
Java 项目打包与部署完全指南:JAR vs WAR,从构建到运行
java·firefox·jar