GetFieldID函数介绍
GetFieldID 是 JNIEnv 接口中用于获取Java类实例字段ID的重要函数。
函数原型
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
参数说明
JNIEnv *env: JNI环境指针jclass clazz: Java类的引用const char *name: 字段名称const char *sig: 字段签名(类型描述符)
返回值
- 成功时返回字段ID (
jfieldID) - 失败时返回
NULL,并在JVM中抛出异常
字段签名规则
基本类型签名
| Java类型 | 签名 |
|---|---|
| boolean | Z |
| byte | B |
| char | C |
| short | S |
| int | I |
| long | J |
| float | F |
| double | D |
| void | V |
引用类型签名
- 对象类型:
L完整类名;(注意结尾的分号)Ljava/lang/String;(String)Lcom/example/MyClass;(自定义类)
- 数组类型:
[+ 元素类型签名[I(int[])[Ljava/lang/String;(String[])
使用示例
1. 访问基本类型字段
// Java代码
public class Calculator {private int result;private boolean isActive;private double value;
}// JNI代码
jclass clazz = env->GetObjectClass(obj);
jfieldID resultFieldID = env->GetFieldID(clazz, "result", "I"); // int类型
jfieldID activeFieldID = env->GetFieldID(clazz, "isActive", "Z"); // boolean类型
jfieldID valueFieldID = env->GetFieldID(clazz, "value", "D"); // double类型
2. 访问对象类型字段
// Java代码
public class Person {private String name;private Date birthDate;
}// JNI代码
jclass clazz = env->GetObjectClass(obj);
jfieldID nameFieldID = env->GetFieldID(clazz, "name", "Ljava/lang/String;"); // String类型
jfieldID dateFieldID = env->GetFieldID(clazz, "birthDate", "Ljava/util/Date;"); // Date类型
3. 访问数组类型字段
// Java代码
public class DataContainer {private int[] numbers;private String[] names;
}// JNI代码
jclass clazz = env->GetObjectClass(obj);
jfieldID numbersFieldID = env->GetFieldID(clazz, "numbers", "[I"); // int[]类型
jfieldID namesFieldID = env->GetFieldID(clazz, "names", "[Ljava/lang/String;"); // String[]类型
完整使用示例
// Java类
public class Student {private String name;private int age;private double[] scores;// getters and setters...
}// JNI函数实现
JNIEXPORT void JNICALL Java_MyClass_updateStudent(JNIEnv *env, jobject obj, jobject studentObj, jstring newName, jint newAge) {// 获取Student类jclass studentClass = env->GetObjectClass(studentObj);// 获取字段IDjfieldID nameFieldID = env->GetFieldID(studentClass, "name", "Ljava/lang/String;");jfieldID ageFieldID = env->GetFieldID(studentClass, "age", "I");jfieldID scoresFieldID = env->GetFieldID(studentClass, "scores", "[D");// 检查字段是否存在if (nameFieldID == NULL || ageFieldID == NULL || scoresFieldID == NULL) {// 字段不存在,处理异常env->ExceptionDescribe();return;}// 设置字段值env->SetObjectField(studentObj, nameFieldID, newName);env->SetIntField(studentObj, ageFieldID, newAge);// 创建新的double数组并设置jdoubleArray newScores = env->NewDoubleArray(3);jdouble scores[] = {95.5, 87.0, 92.5};// 设置数组元素,参数依次为:数组对象,起始位置,长度,源数组env->SetDoubleArrayRegion(newScores, 0, 3, scores);env->SetObjectField(studentObj, scoresFieldID, newScores);
}
注意事项
1. 异常处理
jfieldID fieldID = env->GetFieldID(clazz, "fieldName", "I");
if (fieldID == NULL) {// 字段不存在或签名错误env->ExceptionDescribe(); // 打印异常信息env->ExceptionClear(); // 清除异常return; // 适当的错误处理
}
// GetObjectField 使用 jint value = env->GetIntField(obj, fieldID);
return value;
2. 字段访问权限
GetFieldID可以获取 private、protected、public 字段的ID- 但实际访问时仍需遵循Java访问控制规则
3. 性能考虑
// 推荐:缓存字段ID以提高性能
static jfieldID resultFieldID = NULL;
if (resultFieldID == NULL) {jclass clazz = env->GetObjectClass(obj);resultFieldID = env->GetFieldID(clazz, "result", "I");// 可能需要创建全局引用以长期持有
}
相关函数对比
| 函数 | 用途 | 字段类型 |
|---|---|---|
GetFieldID | 获取实例字段ID | 实例字段 |
GetStaticFieldID | 获取静态字段ID | 静态字段 |
GetFieldID + GetObjectField | 读取对象字段 | 对象引用 |
GetFieldID + GetIntField | 读取int字段 | 基本类型 |
GetFieldID 是JNI中访问Java对象字段的关键函数,正确使用它能够实现C++代码与Java对象状态的交互。
