new T[0]是Java集合转数组类型安全的最优解,因其利用数组运行时组件类型避免ClassCastException,并在内存分配、并发安全和实现一致性上表现最佳。
![集合转数组的类型安全:解析 new t[0] 与指定长度数组在变量转换中的损耗](https://img.php.cn/upload/article/001/242/473/177831954065971.jpeg)
Java中集合转数组,类型安全的核心在于让运行时知道你要什么类型,而不是靠编译期泛型声明。new T[0]之所以成为推荐写法,并非因为它“看起来简洁”,而是它在类型推断、内存分配和并发场景下综合表现最优。
为什么 new T[0] 能保证类型安全
泛型在运行时被擦除,List
- 传 new String[0] → 方法内部创建新的 String[size] 并返回,类型与变量声明完全一致
- 传 new String[list.size()] → 同样能成功,但类型安全不依赖于长度,而依赖于数组的组件类型
- 传 new Object[0] 或直接调用无参 toArray() → 返回 Object[],赋值给 String[] 会编译通过、运行时报错
指定长度数组的实际损耗在哪
表面看,预分配 list.size() 长度的数组似乎更“精准”,但真实开销常被低估:
- size() 调用可能有成本:LinkedList、CopyOnWriteArrayList 等实现的 size() 不是 O(1),某些场景需遍历或快照计算
- 并发下 size 失准:调用 size() 和 toArray() 之间若集合被修改,预分配长度可能不足,触发扩容逻辑(即新建数组 + 复制),反而多一次内存分配
- 冗余对象残留:即使长度刚好,new String[list.size()] 创建的数组仍存在于栈/局部变量中,而 new String[0] 在多数 JVM 中已被逃逸分析优化为零开销
new T[0] 在不同集合实现中的行为一致性
ArrayList 和 LinkedList 对 toArray(T[]) 的处理略有差异,但 new T[0] 能屏蔽这些细节:
- ArrayList:传入数组长度 ≥ size 时,会在索引 size 处写 null;传 [0] 则必然新建,行为确定
- LinkedList:不置 null,只填前 size 个位置;若你传了非空数组又误读剩余位,易引入脏数据;传 [0] 彻底回避该风险
- 统一用 new T[0],就不用关心底层是哪种 List,也不用假设“剩余位置是否清空”
泛型方法中如何传递 T[]
在泛型类或方法里不能直接写 new T[0](因类型擦除),此时需由调用方提供模板数组:
- 正确方式:
<t> T[] toTypedArray(List<t> list, T[] template) { return list.toArray(template); }</t></t> - 调用:
String[] r = toTypedArray(myList, new String[0]); - 避免用 Class
+ Array.newInstance,那会多一层反射开销,且仍需强转

















