JNI调用中填充Java空数组后返回仍为空的问题排查
问题根源
- Java数组不可动态扩容:你在Java中初始化的是长度为0的空数组,Java数组一旦创建长度就固定,无法向其中添加新元素。
- JNI参数传递特性:JNI中对象引用是按值传递的。你在native代码中创建了新的
jobjectArray并赋值给局部变量array,但这只会修改局部变量的引用,不会改变Java层原本的数组引用。
解决方案1:从Native方法返回新数组
修改Java层的native方法,让它直接返回填充好的数组,替代传入空数组的方式。
Java代码修改:
// 定义native方法返回MyClass数组 native MyClass[] fillupArray(); // 调用方式 MyClass[] array = nativeLib.fillupArray();
Native代码修改:
extern "C" JNIEXPORT jobjectArray JNICALL Java_com_example_jniexample_fillupArray(JNIEnv *env, jclass jniexampleClass) { jclass clazz = env->FindClass("com/example/jniexample$MyClass"); if (clazz == nullptr) return nullptr; jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); if (constructor == nullptr) return nullptr; jfieldID srNo = env->GetFieldID(clazz, "srNo", "I"); jfieldID name = env->GetFieldID(clazz, "name", "Ljava/lang/String;"); const int N = 5; // 定义要填充的元素数量 jobjectArray newArray = env->NewObjectArray(N, clazz, nullptr); if (newArray == nullptr) return nullptr; jstring personStr = env->NewStringUTF("Person"); // 正确创建Java字符串 for (int i = 0; i < N; ++i) { jobject obj = env->NewObject(clazz, constructor); if (obj == nullptr) continue; env->SetIntField(obj, srNo, i); env->SetObjectField(obj, name, personStr); env->SetObjectArrayElement(newArray, i, obj); env->DeleteLocalRef(obj); // 释放局部引用避免内存泄漏 } // 释放临时引用 env->DeleteLocalRef(personStr); env->DeleteLocalRef(clazz); return newArray; }
解决方案2:使用Holder对象传递数组引用
如果必须通过参数传递结果,可以用单元素二维数组作为Holder,让Native代码修改Holder内部的数组引用。
Java代码修改:
// 定义native方法接收Holder数组 native void fillupArray(MyClass[][] holder); // 调用方式 MyClass[][] holder = new MyClass[1][]; nativeLib.fillupArray(holder); MyClass[] array = holder[0]; // 从Holder中获取填充好的数组
Native代码修改:
extern "C" JNIEXPORT void JNICALL Java_com_example_jniexample_fillupArray(JNIEnv *env, jclass jniexampleClass, jobjectArray holder) { jclass clazz = env->FindClass("com/example/jniexample$MyClass"); if (clazz == nullptr) return; jmethodID constructor = env->GetMethodID(clazz, "<init>", "()V"); if (constructor == nullptr) return; jfieldID srNo = env->GetFieldID(clazz, "srNo", "I"); jfieldID name = env->GetFieldID(clazz, "name", "Ljava/lang/String;"); const int N = 5; jobjectArray newArray = env->NewObjectArray(N, clazz, nullptr); if (newArray == nullptr) return; jstring personStr = env->NewStringUTF("Person"); for (int i = 0; i < N; ++i) { jobject obj = env->NewObject(clazz, constructor); if (obj == nullptr) continue; env->SetIntField(obj, srNo, i); env->SetObjectField(obj, name, personStr); env->SetObjectArrayElement(newArray, i, obj); env->DeleteLocalRef(obj); } // 将新数组设置到Holder的第一个元素 env->SetObjectArrayElement(holder, 0, newArray); // 释放临时引用 env->DeleteLocalRef(personStr); env->DeleteLocalRef(clazz); env->DeleteLocalRef(newArray); }
其他必须修复的问题
- 字符串创建错误:原代码中
jobject p = (jobject) "Person";是非法操作,必须使用env->NewStringUTF("Person")创建Java字符串对象,否则会导致JNI崩溃。 - 局部引用释放:JNI中创建的局部对象(如
jobject、jclass)需要手动调用DeleteLocalRef释放,避免内存泄漏。 - 错误检查:调用JNI核心方法(如
FindClass、GetMethodID)后,需检查返回值是否为nullptr,及时终止流程避免后续错误。 - N的定义:原代码中未定义
N的值,需明确指定要填充的元素数量。
内容的提问来源于stack exchange,提问作者Santosh P.
相关产品推荐
相关产品推荐

