Java中不能直接用new T[n]创建泛型数组,因类型擦除导致编译器将其替换为Object[n],JVM无法保证运行时类型安全,故编译期禁止;安全做法仅有两种:一是具体类型数组转型,二是Array.newInstance(Class, length)动态创建。

Java 中不能直接用 new T[n] 创建泛型数组,这是由类型擦除决定的硬性限制。真正安全、可维护的做法只有两种:一种是借助具体类型数组转型(适合已知元素类型且上下文可控),另一种是通过 Array.newInstance() 配合 Class 对象动态创建(推荐用于通用工具方法)。关键不是“怎么写出来”,而是如何避免运行时 ClassCastException 或 ArrayStoreException。
为什么 new T[10] 一定报错?
编译器在泛型代码编译后会把所有 T 替换为 Object(无边界时)或其上界类型。如果允许 new T[10],实际生成的字节码就是 new Object[10],但语义上你期望的是 String[] 或 Integer[] 这样的具体数组类型。JVM 在运行时无法验证该数组是否真能安全存入 T 类型对象,所以编译阶段就禁止这种写法,防止类型系统被绕过。
方式一:用具体类型数组转型(简单直接)
适用于构造时已明确知道元素类型,且不对外暴露原始数组引用的场景。本质是“先有实类型,再套泛型壳”。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 声明泛型字段时用
T[],但初始化时传入一个真实类型的数组,例如String[] - 不要把泛型数组赋值给
Object[]引用,否则可能触发ArrayStoreException - 示例:安全写法:
String[] arr = new String[5]; GenericArray<String> ga = new GenericArray<>(arr); - 示例:危险写法:
Object[] objArr = (Object[]) ga.getArray(); objArr[0] = new Integer(1); // 运行时报 ArrayStoreException
方式二:用 Array.newInstance(Class, length)(通用推荐)
这是唯一能在运行时保留组件类型信息的合法手段。它要求你显式提供 Class<T> 实参,比如 String.class,从而让 JVM 知道该创建什么类型的数组。
立即学习“Java免费学习笔记(深入)”;
- 必须由调用方传入真实的 Class 对象,
T.class是非法的(因为 T 已擦除) - 返回值是
Object,需强制转为T[],编译器会提示 unchecked 警告——只要确保传入的clazz和实际使用类型一致,就是安全的 - 常见错误:把
Array.newInstance(String.class, 3)的结果赋给Object[]后往里塞非 String 对象 - 正确用法示例:
T[] arr = (T[]) Array.newInstance(clazz, size);,后续只通过arr引用操作
替代方案:优先考虑集合而不是数组
除非有明确性能要求(如高频随机访问、内存敏感)、对接旧 API(如 JNI、反射方法参数)、或需要数组协变特性(如 String[] 可赋值给 Object[]),否则应首选 ArrayList<T> 等泛型集合。
- 集合天然支持泛型,编译期强校验,无转型警告,无运行时类型风险
- 长度可变、API 丰富(add/remove/contains/stream),开发效率和可维护性更高
- 若最终必须输出数组,可用
list.toArray(new T[0])(推荐空数组形式,避免不必要的扩容) - 注意:
list.toArray(new T[n])中若 n 大于 list size,多余位置填null;若小于,则新建数组,这点和new T[n]逻辑不同

















