java反射创建数组的关键是安全存取异构数据:用array.newinstance()创建运行时类型数组,原始类型须用int.class等;混合类型用object[]+class[]元信息封装;原始数组需用array.getxxx/setxxx访问,动态容器应封装类型校验与装箱转换。

Java 反射中创建数组对象本身不难,但用于封装异构数据结构(如混合类型、运行时才知元素类型和长度)时,关键在于绕过泛型擦除、正确处理原始类型、统一访问接口,并避免 ArrayStoreException 或 IllegalArgumentException。核心不是“造一个数组”,而是“让这个数组能安全存、可统一读、适配未知类型”。
用 Array.newInstance() 创建运行时确定类型的数组
这是最直接的方式,适用于已知组件类型(Class 对象)和长度的场景:
- 对引用类型:传入
String.class、MyBean.class等即可 - 对原始类型:必须用
int.class、boolean.class(不能用Integer.class),否则抛IllegalArgumentException - 支持多维:例如
Array.newInstance(int.class, 3, 4)创建 3×4 的 int[][]
示例:
Class> elementType = String.class; int length = 5; Object arr = Array.newInstance(elementType, length); // 返回 Object,实际是 String[] Array.set(arr, 0, "hello"); // 安全写入 String s = (String) Array.get(arr, 0); // 安全读取
封装异构结构:用 Object[] 作为底层容器 + 类型元信息
若元素类型在运行时才动态混合(比如一行数据含 String、Double、LocalDateTime),不要强行用泛型数组(如 T[]),而应:
- 统一用
Object[]存储所有值(它能容纳任意引用类型) - 额外维护一个
Class[]或Type[]数组,记录每个位置的实际逻辑类型 - 提供类型安全的 getter:根据索引查元信息,再做强制转换或装箱/拆箱
这样既规避了原始类型无法放入 Object[] 的问题(原始类型自动装箱),又保留了类型语义,便于后续序列化或校验。
处理原始类型数组的特殊性
反射创建原始类型数组后,不能用 Object[] 方式访问 —— 它们不是 Object 的子类。必须用 Array.getXXX() / Array.setXXX() 系列方法:
-
Array.getInt(arr, i)、Array.setBoolean(arr, i, true) - 若你封装的容器需统一 API,可在内部判断数组是否为原始类型(
arr.getClass().getComponentType().isPrimitive()),再分发到对应方法 - 避免直接转型:
(int[]) arr是合法的,但(Object[]) arr对原始数组会 ClassCastException
构建动态容器类的关键设计点
一个实用的异构容器(如 DynamicRow)可包含:
- 私有字段:
private final Object array;(存储反射创建的数组) - 私有字段:
private final Class> componentType;(记录真实组件类型) - 构造方法接收
Class> type, int len,调用Array.newInstance(type, len) - 泛型友好的 setter/getter:如
<t> T get(int i, Class<t> expected)</t></t>,内部校验类型兼容性并转换 - 重写
toString()和toArray()时注意原始类型需先转包装类数组(如int[] → Integer[])
这种设计不依赖泛型数组,不破坏类型安全,且能自然支持 JSON 序列化(如 Jackson 可识别 Object[] 内容)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











