Android C/C++ NDK:如何从C层修改Java传递的String变量?
在JNI中为Java的String变量赋值的正确方法
原代码的问题分析
你遇到的编译错误**“意外的参数声明”**,主要来自以下几个问题:
- 类型不匹配:
jstring是JNI对应Java String的专用类型,不能直接将C风格字符串(如"HI WORLD")赋值给它,必须通过JNIEnv提供的方法创建合法的jstring对象。 - 缺少返回值:函数声明为返回
jstring类型,但代码中没有任何return语句,违反了函数的返回约定。 - Java String特性限制:Java的String是不可变对象,且JNI参数传递是值传递,修改JNI函数中的形参
test不会影响Java层的原变量。
解决方案1:JNI函数返回新字符串,Java层接收赋值
这是最直接的实现方式,利用JNI返回新字符串,Java层将返回值重新赋值给原变量。
Java代码修改:
String test = ""; // 接收JNI返回的新字符串,覆盖原变量 test = stringFromJNI(test);
C代码修改:
#include <jni.h> #include <string> extern "C" JNIEXPORT jstring JNICALL Java_com_mduneau_compass3_MainActivity_stringFromJNI( JNIEnv* env, jobject obj, jstring test) { // 创建C++字符串,再转为JNI的jstring对象返回 std::string new_str = "HI WORLD"; return env->NewStringUTF(new_str.c_str()); }
解决方案2:直接修改Java类的成员变量
如果test是类的成员变量,可以通过JNI直接操作对象的字段来修改值,无需传递参数。
Java代码示例:
public class MainActivity { // 类成员变量test private String test = ""; public void updateTest() { // 调用JNI函数修改成员变量 modifyTestString(); } // 声明native方法,无需参数 native void modifyTestString(); }
C代码示例:
#include <jni.h> #include <string> extern "C" JNIEXPORT void JNICALL Java_com_mduneau_compass3_MainActivity_modifyTestString( JNIEnv* env, jobject obj) { // 获取当前对象的类 jclass cls = env->GetObjectClass(obj); if (cls == nullptr) { return; } // 获取成员变量test的字段ID,签名"Ljava/lang/String;"对应Java的String类型 jfieldID test_field_id = env->GetFieldID(cls, "test", "Ljava/lang/String;"); if (test_field_id == nullptr) { env->DeleteLocalRef(cls); return; } // 创建要赋值的新字符串 std::string new_str = "HI WORLD"; jstring j_new_str = env->NewStringUTF(new_str.c_str()); // 设置对象的test字段值 env->SetObjectField(obj, test_field_id, j_new_str); // 释放局部引用,避免内存泄漏 env->DeleteLocalRef(j_new_str); env->DeleteLocalRef(cls); }
内容的提问来源于stack exchange,提问作者Mary
相关产品推荐
相关产品推荐

