Java 不支持泛型数组(如 List<String>[] 或 T[]),因类型擦除导致运行时无泛型信息,编译器禁止创建;JNI 中实际仅支持 Object[] 或基本类型数组(如 String[]、int[])的传递,C 侧需用 jobjectArray 或对应 JNI 数组类型处理,不可直接使用泛型指针。

Java 中没有真正的“泛型数组”——像 List<String>[] 或 T[] 这类写法在运行时会被类型擦除,且 JVM 不允许直接创建泛型数组(编译会报错)。所以所谓“泛型数组”的 JNI 传递,实际只可能是以下两类情形之一:
1. Java 侧是 Object[] 或其子类数组(如 String[]、Integer[]),C 侧按 jobjectArray 处理
这是最常见也最可行的方式。例如:
- Java 方法声明:
public native void processStringArray(String[] arr); - C 侧接收为:
jobjectArray jarr,而非某种“泛型指针” - 需逐个取出元素:
jstring elem = (jstring) (*env)->GetObjectArrayElement(env, jarr, i); - 不能假设数组元素是同一类型(运行时可能混入其他引用),需做类型检查(
IsInstanceOf)或依赖业务约束
2. Java 侧用原始类型数组(int[]、byte[] 等),C 侧用对应 JNI 数组类型 + 元素指针
这类不涉及泛型擦除,映射明确稳定:
-
int[]→jintArray→jint*(通过GetIntArrayElements获取) -
byte[]→jbyteArray→jbyte*(常用于 DirectByteBuffer 底层内存) - 注意:返回的指针是 JVM 内部缓冲区地址,不可长期持有或跨 JNI 调用复用;必须配对调用
ReleaseXXXArrayElements - 若需持久访问(如 GPU 内存),应改用
DirectByteBuffer,其GetDirectBufferAddress返回的地址可安全保留并传给后续 native 函数
3. “T[]” 形式泛型数组的典型错误与替代方案
Java 中写 T[] arr 实际会被编译器转成 Object[],并在运行时插入类型检查。JNI 层无法识别 T 是什么——JVM 没有泛型数组的运行时类型信息。
立即学习“Java免费学习笔记(深入)”;
- 不要尝试把
T[]当作某种模板化指针传入 C;C 无法获知元素真实类型 - 若需类型安全传递,应在 Java 层封装为具体类型数组(如
MyData[]),并在 C 中通过GetObjectClass+GetMethodID反射调用其 getter 方法 - 更高效的做法:定义扁平化结构(如用
float[]存坐标 xyz,而非Point3D[]),由 C 直接解析内存布局
4. 安全传递“逻辑泛型集合”的推荐做法
当业务需要类似泛型集合的跨语言交互时,建议绕过数组类型擦除问题:
- Java 侧统一用
ByteBuffer(尤其allocateDirect)承载原始数据,C 侧用GetDirectBufferAddress获取裸指针 - 配套传一个
int或long表示元素数量、步长和数据格式(如每个元素占 12 字节,含 3 个 float) - 复杂对象序列化为 Protobuf/FlatBuffers 二进制,Java 和 C 共享 schema,避免运行时类型推理
- 若必须传递对象数组,用
jobjectArray+ 显式 class ID 或 tag 字段标识每项语义类型


















