在上一章(《多语言编程之 C and Java:JNI 30 分钟入门》)中讲解了 JNI 的基本使用。这一章将讨论一些更加实用的用法:如何在 JNI 中访问 Java 对象的成员变量或静态变量,以及回调 Java 中的成员方法或静态方法。
1 JNI 访问 Java 成员变量
1.1 实例
Java 实现
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 实现
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() 原型如下:
jfieldID GetFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig);
继续阅读