You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JNI调用中填充Java空数组后返回仍为空的问题排查

问题根源

  1. Java数组不可动态扩容:你在Java中初始化的是长度为0的空数组,Java数组一旦创建长度就固定,无法向其中添加新元素。
  2. 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);
}

其他必须修复的问题

  1. 字符串创建错误:原代码中jobject p = (jobject) "Person";是非法操作,必须使用env->NewStringUTF("Person")创建Java字符串对象,否则会导致JNI崩溃。
  2. 局部引用释放:JNI中创建的局部对象(如jobject、jclass)需要手动调用DeleteLocalRef释放,避免内存泄漏。
  3. 错误检查:调用JNI核心方法(如FindClass、GetMethodID)后,需检查返回值是否为nullptr,及时终止流程避免后续错误。
  4. N的定义:原代码中未定义N的值,需明确指定要填充的元素数量。

内容的提问来源于stack exchange,提问作者Santosh P.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 13:01:03