在上一章(《多语言编程之 C and Java:JNI 30 分钟入门》)中讲解了 JNI 的基本使用。这一章将讨论一些更加实用的用法:如何在 JNI 中访问 Java 对象的成员变量或静态变量,以及回调 Java 中的成员方法或静态方法。
1 JNI 访问 Java 成员变量
1.1 实例
Java 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package transvar; public class TransVar{ static{ System.loadLibrary("hello"); } //成员变量(字段) private int age = 88; private String name = "Jims"; //静态成员变量 private static int years = 20; private native void modifyInstanceVariable(); } |
这个 Java 类中包含 3 个私有成员变量,名为 age 的 int 型变量, 名为 name 的 String 型变量和一个名为 years 的 int 型静态变量。我们将在使用 C 来访问或修改这些成员变量。
C 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
JNIEXPORT void JNICALL Java_transvar_TransVar_modifyInstanceVariable (JNIEnv *env, jobject obj) { //获取 this object 的类 jclass thisClass = (*env)->GetObjectClass(env,obj); if(thisClass == NULL) { printf("thisClass null\n"); } //获取字段ID jfieldID fidAge = (*env)->GetFieldID(env, thisClass, "age", "I"); jfieldID fidName = (*env)->GetFieldID(env, thisClass, "name", "Ljava/lang/String;"); jfieldID fidYear = (*env)->GetStaticFieldID(env, thisClass, "years", "I"); //获取字段 jint age = (*env)->GetIntField(env, obj, fidAge); jint years = (*env)->GetStaticIntField(env, obj, fidYear); jstring name = (*env)->GetObjectField(env, obj, fidName); const char* pszName = (*env)->GetStringUTFChars(env, name, NULL); printf("[%d Years Later for %s] \n", years, pszName); (*env)->ReleaseStringUTFChars(env, name, pszName); age += years; //修改成员变量 (*env)->SetIntField(env, obj, fidAge, age); } |
1.2 访问 Java 变量
在 JNI 中我们获取了这 3 个变量,并对 age 变量进行了修改。
由这段代码可以看出,访问 Java 成员变量的一般步骤为:
- 通过 GetObjectClass() 获取 Java 类的引用。
- 通过 GetFieldID()/GetStaticFieldID() 从 Java 类中获取 FieldID 。
- 基于 FieldID, 通过 Get<type>Field()/GetStatic<type>Field() 取回变量。
- 基于 FieldID, 通过 Set<type>Field()/GetStatic<type>Field() 修改变量。
GetFieldID()/GetStaticFieldID() 原型如下:
1 2 |
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig); |