ArrayList不能存原始类型因Java泛型不支持基本类型,需用包装类导致装箱开销;初始化应预设容量避免频繁扩容;非线程安全,多线程需用CopyOnWriteArrayList等替代;存可变对象需深拷贝防状态污染。

ArrayList 是 Java 中最常用的动态数组实现,适合存储业务中数量不确定、需要频繁随机访问的列表数据;但它不适合高并发写入或频繁在头部插入/删除的场景。
为什么不能直接用 ArrayList 存原始类型(如 int)?
Java 的泛型不支持基本类型,ArrayList 只能存对象。写 new ArrayList 会编译报错。必须用包装类:
ArrayList<integer> ids = new ArrayList(); // ✅ // ArrayList<int> ids = new ArrayList(); // ❌ 编译失败</int></integer>
这带来两个隐含成本:自动装箱(int → Integer)和额外内存开销。如果业务数据量极大(如百万级 ID),且只做数值计算,考虑改用 int[] 或第三方库(如 Eclipse Collections 的 IntArrayList)。
ArrayList 初始化时要不要指定初始容量?
要——尤其当你能预估数据规模时。默认构造函数用的是空数组,第一次 add() 就触发扩容(1.5 倍增长),反复扩容会复制数组、影响性能。
常见做法:
- 已知大概数量(如订单列表通常 ≤ 50 条):
new ArrayList(64) - 从其他集合构建:
new ArrayList(otherList)会直接用其size()作为初始容量 - 完全无法预估(如日志流实时聚合):保持默认,但避免在循环里反复
add()前不预留
业务中往 ArrayList 添加数据时容易踩哪些坑?
最典型的是在多线程环境下直接共享修改:
-
ArrayList不是线程安全的,add()和get()同时调用可能抛ConcurrentModificationException或返回脏数据 - 别用
Collections.synchronizedList(new ArrayList())简单包裹——它只保证单个方法原子性,复合操作(如先size()再get(i))仍需手动同步 - 真正需要并发写入时,优先选
CopyOnWriteArrayList(读多写少)或BlockingQueue(生产者-消费者模型)
另一个隐蔽问题:存可变对象(如自定义 Order 类)后,外部修改该对象字段,ArrayList 里的引用指向的还是同一对象——数据状态就“意外”变了。必要时在 add() 前做深拷贝。
实际业务里,ArrayList 的“动态增长”本质是数组扩容,不是无限伸缩。当数据规模持续超预期(比如从百条涨到十万条),就得重新评估是否该切分存储、引入数据库分页,或者换用更适合的结构(如跳表、B+ 树)。别让它扛本不该扛的量。










