- 成员
- 方法
#1. 成员
Java中成员变量分为普通成员变量和静态成员变量。普通成员变量也称为类实例成员变量,所有类的实例都有自己的成员变量副本;静态成员变量也称为类成员变量,所有类的实例共享类的静态成员变量。
JNI层也据此提供了两类访问成员变量的方式:一类是访问类实例的成员变量,另一类是访问类的成员变量。
1.1 访问实例成员
访问类实例成员分为两个步骤:
- 调用GetFiledID去获取类的field ID。
jfieldID fId = env->GetFieldID(objClazz, "s", "Ljava/lang/String;");
- 调用Get<type>Field获取实例成员,Get<type>Field接受field ID作为参数。
jstring jstr = (jstring) env->GetObjectField(obj, fId);
1.1.1 GetObjectClass
获取实例所属的类。
jclass GetObjectClass(JNIEnv *env, jobject obj);
1.1.2 GetFieldID
通过指定成员变量的名字和签名,获取类实例的成员ID。获取的ID通过Get<type>Field和Set<type>Field函数集可以对类实例成员进行读写。
jfieldID GetFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
1.1.3 Get<type>Field Routines
Get系列函数用来获取类实例成员变量的值。参数fieldID即是通过调用GetFieldID获得。
NativeType Get<type>Field(JNIEnv *env, jobject obj,jfieldID fieldID);
Get<type>Field Routine Name | Native Type |
---|---|
GetObjectField() | jobject |
GetBooleanField() | jboolean |
GetByteField() | jbyte |
GetCharField() | jchar |
GetShortField() | jshort |
GetIntField() | jint |
GetLongField() | jlong |
GetFloatField() | jfloat |
GetDoubleField() | jdouble |
1.1.4 Set<type>Field Routines
Set系列函数集用来给类实例成员变量设置值。参数fieldID即是通过调用GetFieldID获得。
void Set<type>Field(JNIEnv *env, jobject obj, jfieldID fieldID,NativeType value);
Set<type>Field Routine | Native Type |
---|---|
SetObjectField() | jobject |
SetBooleanField() | jboolean |
SetByteField() | jbyte |
SetCharField() | jchar |
SetShortField() | jshort |
SetIntField() | jint |
SetLongField() | jlong |
SetFloatField() | jfloat |
SetDoubleField() | jdouble |
1.1.5 示例
public class InstanceFieldAccess {
static {
System.loadLibrary("jnitest");
}
public String s;
public native void accessField();
}
JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_InstanceFieldAccess_accessField
(JNIEnv *env, jobject obj) {
jfieldID fId;
jstring jstr;
//Get a reference to obj's class.
jclass objClazz = env->GetObjectClass(obj);
if (objClazz == nullptr) {
return;
}
//Get field s of instance obj.
fId = env->GetFieldID(objClazz, "s", "Ljava/lang/String;");
if (fId == nullptr) {
return;
}
//Read the instance field s.
jstr = (jstring) env->GetObjectField(obj, fId);
if (jstr == nullptr) {
return;
}
const char *str = env->GetStringUTFChars(jstr, nullptr);
printf(" c.s = \"%s\"\n", str);
env->ReleaseStringUTFChars(jstr, str);
jstr = env->NewStringUTF("123");
if (jstr == nullptr) {
return;
}
//Overwrite the instance field.
env->SetObjectField(obj, fId, jstr);
}
1.2 访问类成员
1.2.1 GetStaticFieldID
通过指定类成员的名字和签名,获取类的成员ID。获取的ID通过GetStatic<type>Field和SetStatic<type>Field函数集可以对类成员进行读写。
jfieldID GetStaticFieldID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
1.2.2 GetStatic<type>Field Routines
Get系列函数集用来获取类成员变量的值。参数fieldID即是通过调用GetStaticFieldID获得。
NativeType GetStatic<type>Field(JNIEnv *env, jclass clazz,jfieldID fieldID);
GetStatic<type>Field Routine Name | Native Type |
---|---|
GetStaticObjectField() | jobject |
GetStaticBooleanField() | jboolean |
GetStaticByteField() | jbyte |
GetStaticCharField() | jchar |
GetStaticShortField() | jshort |
GetStaticIntField() | jint |
GetStaticLongField() | jlong |
GetStaticFloatField() | jfloat |
GetStaticDoubleField() | jdouble |
1.2.3 SetStatic<type>Field Routines
Set系列函数集用来设置类成员变量的值。参数fieldID即是通过调用GetStaticFieldID获得。
void SetStatic<type>Field(JNIEnv *env, jclass clazz,jfieldID fieldID, NativeType value);
SetStatic<type>Field Routine | Native Type |
---|---|
SetStaticObjectField() | jobject |
SetStaticBooleanField() | jboolean |
SetStaticByteField() | jbyte |
SetStaticCharField() | jchar |
SetStaticShortField() | jshort |
SetStaticIntField() | jint |
SetStaticLongField() | jlong |
SetStaticFloatField() | jfloat |
SetStaticDoubleField() | jdouble |
1.2.4 示例
public class InstanceFieldAccess {
static {
System.loadLibrary("jnitest");
}
public static int num;
public native void accessStaticField();
}
JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_InstanceFieldAccess_accessStaticField
(JNIEnv *env, jobject obj) {
jclass clazz;
jfieldID fid;
clazz = env->GetObjectClass(obj);
if (clazz == nullptr) {
return;
}
fid = env->GetStaticFieldID(clazz, "num", "I");
if (fid == nullptr) {
return;
}
jint num = env->GetStaticIntField(clazz, fid);
printf(" StaticFieldAccess.num = %d\n", num);
env->SetStaticIntField(clazz, fid, 300);
}
#2. 方法
Java中方法分为实例方法和类方法两种。JNI层提供了对应函数集来进行相应的函数调用。
2.1 访问实例方法
JNI层访问实例方法分为两个步骤:
- 通过GetMethodID查找实例方法,获取对应jmethodID。查找的是基于函数名字和函数签名。
- 调用Call<type>Method调用实例方法,Call<type>Method接受jmethodID作为参数。
2.1.1 GetMethodID
通过指定实例方法的名字和签名来获取类实例的方法ID。函数签名是以函数参数类型和返回值类型作为描述符。
jmethodID GetMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
签名示例:
private native String getLine(String);
//Signature
"(Ljava/lang/String;)Ljava/lang/String;"
2.1.2 Call<type>Method Routines
Call<type>Method,Call<type>MethodA和Call<type>MethodV函数系列用来调用实例方法。他们的区别在于传递函数所需参数的方式不同。
- Call<type>Method Routines通过可变参数列表传递函数参数。
- Call<type>MethodA Routines通过jvalues数组传递函数参数。
- Call<type>MethodV Routines通过va_list传递函数参数。
NativeType Call<type>Method(JNIEnv *env, jobject obj,
jmethodID methodID, ...);
NativeType Call<type>MethodA(JNIEnv *env, jobject obj,
jmethodID methodID, const jvalue *args);
NativeType Call<type>MethodV(JNIEnv *env, jobject obj,
jmethodID methodID, va_list args);
Call<type>Method Routine Name | Native Type |
---|---|
CallVoidMethod() | void |
CallVoidMethodA() | |
CallVoidMethodV() | |
CallObjectMethod() | jobject |
CallObjectMethodA() | |
CallObjectMethodV() | |
CallBooleanMethod() | jboolean |
CallBooleanMethodA() | |
CallBooleanMethodV() | |
CallByteMethod() | jbyte |
CallByteMethodA() | |
CallByteMethodV() | |
CallCharMethod() | jchar |
CallCharMethodA() | |
CallCharMethodV() | |
CallShortMethod() | jshort |
CallShortMethodA() | |
CallShortMethodV() | |
CallIntMethod() | jint |
CallIntMethodA() | |
CallIntMethodV() | |
CallLongMethod() | jlong |
CallLongMethodA() | |
CallLongMethodV() | |
CallFloatMethod() | jfloat |
CallFloatMethodA() | |
CallFloatMethodV() | |
CallDoubleMethod() | jdouble |
CallDoubleMethodA() | |
CallDoubleMethodV() |
2.1.3 CallNonvirtual<type>Method Routines
CallNonvirtual<type>Method,CallNonvirtual<type>MethodA和CallNonvirtual<type>MethodV函数系列用来调用实例方法。其中<type>所调用函数的返回值类型。
NativeType CallNonvirtual<type>Method(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, ...);
NativeType CallNonvirtual<type>MethodA(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, const jvalue *args);
NativeType CallNonvirtual<type>MethodV(JNIEnv *env, jobject obj,
jclass clazz, jmethodID methodID, va_list args);
2.1.4 示例
public class MethodCall {
static {
System.loadLibrary("jnitest");
}
private void callback() {
System.out.println("In Java.");
}
public native void nativeMethod();
}
JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_MethodCall_nativeMethod
(JNIEnv *env, jobject obj) {
jclass clazz;
jmethodID mid;
clazz = env->GetObjectClass(obj);
if (clazz == nullptr) {
return;
}
mid = env->GetMethodID(clazz, "callback", "()V");
if (mid == nullptr) {
return;
}
env->CallVoidMethod(obj,mid);
}
2.2 访问类方法
2.2.1 GetStaticMethodID
通过指定类方法的名字和签名,获取类方法ID。
jmethodID GetStaticMethodID(JNIEnv *env, jclass clazz,const char *name, const char *sig);
2.2.2 CallStatic<type>Method Routines
CallStatic<type>Method,CallStatic<type>MethodA和CallStatic<type>MethodV函数系列用来调用类方法。
NativeType CallStatic<type>Method(JNIEnv *env, jclass clazz,
jmethodID methodID, ...);
NativeType CallStatic<type>MethodA(JNIEnv *env, jclass clazz,
jmethodID methodID, jvalue *args);
NativeType CallStatic<type>MethodV(JNIEnv *env, jclass clazz,
jmethodID methodID, va_list args);
CallStatic<type>Method Routine Name | Native Type |
---|---|
CallStaticVoidMethod() | void |
CallStaticVoidMethodA() | |
CallStaticVoidMethodV() | |
CallStaticObjectMethod() | jobject |
CallStaticObjectMethodA() | |
CallStaticObjectMethodV() | |
CallStaticBooleanMethod() | jboolean |
CallStaticBooleanMethodA() | |
CallStaticBooleanMethodV() | |
CallStaticByteMethod() | jbyte |
CallStaticByteMethodA() | |
CallStaticByteMethodV() | |
CallStaticCharMethod() | jchar |
CallStaticCharMethodA() | |
CallStaticCharMethodV() | |
CallStaticShortMethod() | jshort |
CallStaticShortMethodA() | |
CallStaticShortMethodV() | |
CallStaticIntMethod() | jint |
CallStaticIntMethodA() | |
CallStaticIntMethodV() | |
CallStaticLongMethod() | jlong |
CallStaticLongMethodA() | |
CallStaticLongMethodV() | |
CallStaticFloatMethod() | jfloat |
CallStaticFloatMethodA() | |
CallStaticFloatMethodV() | |
CallStaticDoubleMethod() | jdouble |
CallStaticDoubleMethodA() | |
CallStaticDoubleMethodV() |
2.2.3 示例
public class MethodCall {
static {
System.loadLibrary("jnitest");
}
private static void callbackV2() {
System.out.println("Static In Java.");
}
public native void staticNativeCall();
}
JNIEXPORT void JNICALL Java_com_nextlabs_hhu_myapplication_core_MethodCall_staticNativeCall
(JNIEnv *env, jobject obj) {
jclass clazz;
jmethodID mid;
clazz = env->GetObjectClass(obj);
if (clazz == nullptr) {
return;
}
mid = env->GetStaticMethodID(clazz, "callbackV2", "()V");
if (mid == nullptr) {
return;
}
env->CallStaticVoidMethod(clazz,mid);
}
网友评论