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属性

相关推荐
YDS8291 小时前
DeepSeek RAG&MCP + Agent智能体项目 —— 集成ELK日志管理系统和Prometheus监控系统
java·elk·ai·springboot·agent·prometheus·deepseek
骄马之死8 小时前
SpringMVC + SpringBoot 核心知识点总结
java·spring boot·后端
GoGeekBaird9 小时前
Anthropic技能"(Skills)的经验分享
后端
王码码20359 小时前
多台服务器怎么统一看状态?Beszel 轻量监控,搭起来不费事
运维·服务器·后端·安全·阿里云·接口·web
郑洁文10 小时前
基于Spring Boot的流浪动物救助网站
java·spring boot·后端·毕设·流浪动物救助
螺丝钉code10 小时前
JAVA项目 Claude code CLAUDE.md 到底应该怎么写
java·人工智能·claude code
指令集梦境11 小时前
Cursor + Spring Boot实战:从零写一个RESTful API
spring boot·后端·restful
摇滚侠11 小时前
Maven 入门+高深 单一架构案例 54-59
java·架构·maven·intellij-idea
VidDown12 小时前
Webhook 调试器:让第三方回调“原形毕露”
java·开发语言·javascript·编辑器·postman
码云之上12 小时前
聊聊如何设计一个高效、稳定的 Node.js 接入层
前端·后端·node.js