JNI 访问Java的成员变量
在JNI中访问Java对象的属性,通常需要先获取属性的 jfieldID,然后使用相应的函数进行读写操作。

1、访问非静态属性
例1:
//Java代码
public class MyClass { private int mValue; public MyClass(int value) { mValue = value; } }
#include <jni.h> #include <iostream> // 假设JNIEnv* env和jobject obj已经被正确设置 // 1. 加载Java类 jclass clazz = env->FindClass("com/example/MyClass"); // 2. 获取属性的jfieldID jfieldID fieldID = env->GetFieldID(clazz, "mValue", "I"); // 3. 读取属性值 jint value = env->GetIntField(obj, fieldID); std::cout << "Read value: " << value << std::endl; // 4. 设置属性值 jint newValue = value + 1; env->SetIntField(obj, fieldID, newValue); std::cout << "New value set: " << newValue << std::endl; // 5. 释放本地引用 env->DeleteLocalRef(clazz);
例2:
//Java代码 public String key = "key"; public native String accessField();
JNIEXPORT jstring JNICALL Java_JniMain_accessField(JNIEnv * env, jobject jobj)
{ //1.获取jclasss jclass jclz = (*env)->GetObjectClass(env,jobj); //2.fieldId key:属性名称, Ljava/lang/String:属性签名 jfieldID fid = (*env)->GetFieldID(env,jclz,"key","Ljava/lang/String;"); //3.得到key 对应的值 //GetXXXField 因为String 是引用类型 所以使用GetObjectField jstring jstr = (*env)->GetObjectField(env,jobj,fid); //4.将jni的string 转换成C的char char * c_str = (*env)->GetStringUTFChars(env,jstr,NULL); //5.生成新的字符串 HBin key char text[30] = "HBin"; stract(text,c_str); //6.C->jni jstring new_str = (*env)->NewStringUTF(env,text); //7.使用set方法 (env)-SetObjectField(env,jobj,fid,new_str); //释放 (*env)->ReleaseStringChars(env,new_str,c_str); return new_str; }
2、访问静态属性
例1:
//Java代码 public static int count = 9; public native void accessStaticField();
//访问静态域还是使用jobject的参数 范围静态函数才是使用jclass的参数 JNIEXPORT void JNICALL Java_JniMain_accessStaticField(JNIEnv * env, jobject jobj) { //1.获取jclasss jclass jclz = (*env)->GetObjectClass(env, jobj); //2.得到fieldId count:属性名称, I:属性签名 jfieldID fid = (*env)->GetFieldID(env, jclz, "count", "I"); jint count = (*env)->GetStaticIntField(env, jclz, fid); //int 不需要转换可以直接使用 count++; (env)->SetStaticIntField(env, jclass, fid, count); }
3、访问数组
//Java代码 public class MyClass { public int[] myIntArray; public MyClass(int[] array) { this.myIntArray = array; } }
例1:
JNIEXPORT void JNICALL Java_com_example_MyClass_accessArray(JNIEnv *env, jobject obj) { //获取jclass jclass clz = env->GetObjectClass(obj); //获取成员变量的Id jfieldID fid = env->GetFieldID(clz, "myIntArray", "[I"); jintArray jArray = env->GetObjectField(obj, fid); // 获取数组长度 jsize len = env->GetArrayLength(jArray); //将JNI数组复制到C数组 jint* buf = new jint[len]; env->GetIntArrayRegion(jArray, 0, len, buf); //更新C数组 buf[0] = 25; //将修改提交到JNI数组中 env->SetIntArrayRegion(jArray, 0, len, buf); //释放C数组 delete [] buf; }
例2:
JNIEXPORT void JNICALL Java_com_example_MyClass_accessArray(JNIEnv *env, jobject obj) { //获取jclass jclass clz = env->GetObjectClass(obj); //获取成员变量的Id jfieldID fid = env->GetFieldID(clz, "myIntArray", "[I"); jintArray jArray = env->GetObjectField(obj, fid); jboolean isCopy; //直接获取指针,C++指针 jint* pArray = env->GetIntArrayElements(jArray, &isCopy); //更新C数组 pArray[0] = 25;//释放数组 //mode:0 - 将数组内容拷贝回JNI数组,并释放C数组 //JNI_COMMIT - 将数组内容拷贝回JNI数组,但不释放C数组 //JNI_ABORT - 不拷贝数组内容,只释放C数组 env->ReleaseIntArrayElements(jArray , pArray, 0); }
访问数组小结:
(1)GetIntArrayRegion:把Java的数组拷贝到 C++ 新建的数组内存区域中。
优点:C++中的改变不会影响Java中的数值
缺点:需要在C++中开辟额外内存空间。数组比较大时,复制元素可能会出现性能问题。
适用场景:适用于需要在C++中处理Java数组的特定区域数据,且不需要修改原始Java数组的场景。这种方式减少了内存分配和释放的开销。
(2)GetIntArrayElements:获取指向数组元素的直接指针,C++代码通过这个指针可以直接操作Java数组的数据。这个函数的最后一个参数是isCopy,让调用者确定返回的c指针是指向副本,还是指向堆中的固定对象。
优点:不用拷贝占用额外的内存,Java和C++中的改版是同步的。
缺点:
适用场景:适用于需要直接操作Java数组内容,且不需要在C++中修改原始Java数组的场景。如果需要在C++中修改数组并同步更新Java中的数据并释放掉C++指针,应使用ReleaseIntArrayElements方法并设置Release_mode为 0;

浙公网安备 33010602011771号