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

如何通过JNI在C中创建Java对象并赋值给Java端声明的变量

现有代码无效的核心原因

  • Java语言是值传递,你传入native方法的myVar是原变量的引用副本,C层对局部参数my_var的赋值仅修改C函数栈上的局部变量,不会回写到Java层的原始myVar变量。
  • 你当前的JNI函数声明不符合JNI规范,缺少强制要求的JNIEnv*和调用上下文参数。

可落地的三种实现方案

方案1:通过返回值回传对象(最简单,推荐)

直接把C层创建的对象作为native方法返回值返回给Java层赋值:
Java端代码:

// 声明native方法,返回值为创建的Object,注意替换为你自己的类方法声明
private native Object c_function();

// 调用逻辑
Object myVar;
myVar = c_function();
System.out.println(myVar);

C端代码(C环境写法,C++可简化调用语法):

#include "jni.h"

// 注意函数名要和你的Java类全限定名对应,示例中com_example_MainActivity替换为你自己的类路径
JNIEXPORT jobject JNICALL Java_com_example_MainActivity_c_1function(JNIEnv *env, jobject thiz)
{
    jclass jcls = (*env)->FindClass(env, "java/lang/Object");
    // 如果是自定义类建议用NewObject调用构造方法初始化,不要直接用AllocObject
    jobject new_obj = (*env)->AllocObject(env, jcls);
    return new_obj;
}

方案2:用长度为1的数组包装变量实现参数回传

如果必须通过参数回传值,可以把变量放到长度为1的数组中,数组是引用对象,修改数组元素会同步到Java层:
Java端代码:

private native void c_function(Object[] arr);

// 调用逻辑
Object myVar;
Object[] wrapArr = new Object[1];
c_function(wrapArr);
myVar = wrapArr[0];
System.out.println(myVar);

C端代码:

#include "jni.h"

JNIEXPORT void JNICALL Java_com_example_MainActivity_c_1function(JNIEnv *env, jobject thiz, jobjectArray wrap_arr)
{
    jclass jcls = (*env)->FindClass(env, "java/lang/Object");
    jobject new_obj = (*env)->AllocObject(env, jcls);
    // 给数组下标0的位置赋值
    (*env)->SetObjectArrayElement(env, wrap_arr, 0, new_obj);
}

方案3:直接操作Java类的成员字段

如果myVar是Java类的成员变量,可以直接在C层获取字段ID后赋值,不需要额外传参:
Java端代码:

// 声明为类的成员变量
private Object myVar;
private native void c_function();

// 调用逻辑
c_function();
System.out.println(myVar);

C端代码:

#include "jni.h"

JNIEXPORT void JNICALL Java_com_example_MainActivity_c_1function(JNIEnv *env, jobject thiz)
{
    // 获取myVar字段的ID,签名Ljava/lang/Object;对应Object类型
    jfieldID field_id = (*env)->GetFieldID(env, (*env)->GetObjectClass(env, thiz), "myVar", "Ljava/lang/Object;");
    jclass jcls = (*env)->FindClass(env, "java/lang/Object");
    jobject new_obj = (*env)->AllocObject(env, jcls);
    // 直接给对象的字段赋值
    (*env)->SetObjectField(env, thiz, field_id, new_obj);
}

注意事项

  • 如果创建的是自定义类对象,不要直接用AllocObject,该方法不会执行类的构造方法,建议用NewObject调用指定构造方法完成初始化,避免未初始化的对象运行报错。
  • 上述示例中创建的都是JNI局部引用,函数执行完后会自动释放,如果你需要在C层长时间持有该对象,需要调用NewGlobalRef转为全局引用,避免被GC回收。
  • C++环境下的JNI代码,JNIEnv的调用语法可以简化为env->FindClass、env->AllocObject,不需要解引用和传入env作为第一个参数。

内容的提问来源于stack exchange,提问作者user7698505

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 22:24:03