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

相关推荐
Neoest28 分钟前
【EasyExcel 填坑日记】“Syntax error on token )“: 一次编译错误在逃 Runtime 的灵异事件
java·eclipse·编辑器
自在极意功。29 分钟前
Web开发中的分层解耦
java·microsoft·web开发·解耦
是一个Bug31 分钟前
ConcurrentHashMap的安全机制详解
java·jvm·安全
断剑zou天涯35 分钟前
【算法笔记】bfprt算法
java·笔记·算法
番石榴AI37 分钟前
java版的ocr推荐引擎——JiaJiaOCR 2.0重磅升级!纯Java CPU推理,新增手写OCR与表格识别
java·python·ocr
码事漫谈1 小时前
VSCode CMake Tools 功能解析、流程与最佳实践介绍
后端
鸽鸽程序猿1 小时前
【项目】【抽奖系统】抽奖
java·spring
火云牌神1 小时前
本地大模型编程实战(38)实现一个通用的大模型客户端
人工智能·后端
码事漫谈2 小时前
从C++/MFC到CEF与TypeScript的桌面架构演进
后端
GoogleDocs2 小时前
基于[api-football]数据学习示例
java·学习