toArray()无参重载返回Object[],强转目标类型数组会抛ClassCastException;正确写法是传入目标类型空数组如new String[0];Java 16+推荐用stream().toList().toArray(String[]::new)。

toArray() 直接调用返回 Object[],不是目标类型数组
Java 的 Collection.toArray() 无参重载永远返回 Object[],哪怕你集合里全是 String。强转成 String[] 会抛 ClassCastException —— 这是最常踩的坑。
根本原因:泛型擦除后,JVM 不知道你要什么类型,只能安全地返回 Object[]。
- 别写:
String[] arr = (String[]) list.toArray();→ 运行时报错 - 正确做法:传入一个带类型的空数组,让方法“照着这个模板造”
- 推荐写法:
String[] arr = list.toArray(new String[0]); - 传
new String[0]比new String[list.size()]更优:HotSpot 对零长数组有优化,且避免了预估 size 错误导致的额外扩容
toArray(T[] a) 的数组长度影响实际行为
传进来的数组 a 长度不是摆设:它直接决定返回值是复用该数组,还是新建一个。
规则很简单:
- 如果
a.length >= collection.size():复用a,未填满部分设为null - 否则:新建一个和 collection 同类型的数组(类型来自
a.getClass().getComponentType()),大小正好是collection.size()
所以这行代码:list.toArray(new String[5]),当 list 有 3 个元素时,返回的仍是那个长度为 5 的数组,后两个元素是 null —— 容易引发 NPE,除非你明确需要这种填充语义。
Stream.toList() + toArray() 是 Java 16+ 更简洁的替代方案
如果你用的是 Java 16 或更高版本,且目标是转成不可变集合再转数组,stream().toList() 比传统 ArrayList 更轻量,再配合 toArray 可读性更好:
List<string> list = Arrays.asList("a", "b", "c");<br>String[] arr = list.stream().toList().toArray(String[]::new);</string>
注意:Stream.toList() 返回的是不可变列表,不支持 add/remove;但如果你只是临时转数组,这点限制通常无关紧要。相比老式 new ArrayList(coll),它少一次对象分配。
Android 开发中要注意 Arrays.asList() 的陷阱
在 Android 上,如果你用 Arrays.asList(primitiveArray) 想转集合再调 toArray(),会发现结果诡异——因为 Arrays.asList() 对基本类型数组只认作单个元素(整个数组是 Object),不是你想的“每个数字一个元素”。
- 错误:
int[] nums = {1,2,3}; Listl = Arrays.asList(nums); // 得到含 1 个元素的列表 - 正确解法:用
IntStream.of(nums).boxed().toArray(Integer[]::new),或手动循环填充 - 结论:基本类型数组不能直接进
Arrays.asList(),这是类型系统限制,不是 API bug
真正麻烦的点在于:错误往往在运行时才暴露,编译器不报错,但逻辑完全不对。遇到数组转集合,先确认原始数据是不是包装类型。










