【Android JNI】在C/C++中调用Java,androidjni
【Android JNI】在C/C++中调用Java,androidjni
JNI名词解释
jclass对应Java类的名字,jobject对应Java实例化后的对象,jfieldID对应Java类成员变量的ID,jmethodID对应Java类方法的ID。
JNI中对Java的调用,通常要先获取jclass,然后生成实例化对象jobject,根据jclass可以获取jfield&jmethodID,有了这几个元素,可以对Java类的成员变量和方法进行操作。
生成Java对象 jobject
根据Java类名字jclass可以生成Java类对象,所以要先获取Java类名字jclass。
获取Java类名 jclass
如果知道Java类全名,可以使用FindClass
函数获取jclass,参数为字符串类型(包名+类名)。或者如果已知实例化后的jobject,可以使用GetObjectClass
函数获取jclass,参数为jobject实例。
jclass FindClass(const char* name);
jclass GetObjectClass(jobject obj);
获取自定义类jclass
比如有包名为package com.lmshao.jniexample;
类名为public class Student{}
,则获取这个Student类名的方法为:
jclass clazz = env->FindClass("com/lmshao/jniexample/Student");
示例:获取内置类jclass
获取Java内置类名方法为:
jclass uuidClass = env->FindClass("java/util/UUID"); // UUID
jclass clazzBoolean = env->FindClass("java.util.HashMap"); // HashMap
示例:通过jobject获取类jclass
如果已知jobject,可以根据jobject来获取jclass,jclass会在接下来获取类成员变量和方法时候用到。
void jniFunction(JNIEnv *env, jobject object) {
jclass clazz = env->GetObjectClass(object);
....
}
生成Java对象 jobject
根据jclass实例化有两种方式,一种是使用AllocObject
隐式调用默认的构造函数实例化,另一种是使用NewObject
和构造函数的jmethodID,显式调用指定签名的构造函数。
NewObject
函数第二个参数jmethodID为构造函数的ID,可以使用GetMethodID
函数获取这个变量。(GetMethodID
函数第二个参数为成员函数的名字,当获取构造函数ID的时候,这个参数指定为<init>
,第三个参数为方法签名,详细参考下面的调用Java类方法段落。)
jobject AllocObject(jclass clazz);
jobject NewObject(jclass, jmethodID, ...);
示例:AllocObject用法
假设有个Student类,接下来要调用默认构造函数进行实例化。
jclass studentClass = env->FindClass("com/lmshao/jniexample/Student");
jobject studentObject = env->AllocObject(studentClass);
示例:NewObject用法
假设Student类有个构造函数为public Student(int mAge)
,接下来调用这个构造函数进行实例化。
jclass studentClass = env->FindClass("com/lmshao/jniexample/Student");
jmethodID constructorMethod = env->GetMethodID(studentClass, "<init>", "(I)V"); // param2: "<init>", param3:构造函数的签名
int age = 26;
jobject studentObject = env->NewObject(studentClass, constructorMethod, (jint)age);
当然这种方法也可以调用没有参数的默认构造函数。
jclass studentClass = env->FindClass("com/lmshao/jniexample/Student");
jmethodID constructorMethod = env->GetMethodID(studentClass, "<init>", "()V");
jobject studentObject = env->NewObject(studentClass, constructorMethod);
Java类成员变量操作 (Set & Get)
获取Java类成员变量ID jfieldID
要对Java类成员变量进行操作,必须要先知道成员变量的ID。根据jclass可以使用GetFieldID
或GetStaticFieldID
函数获取成员变量ID(jfieldID),前者表示非静态变量后者表示静态成员变量,用法一样。参数1为jclass,参数2为成员变量名,参数3为成员变量的签名。关于Java基本数据类型的JNI签名可以查看上一篇博客 的签名部分。
jfieldID GetFieldID(jclass clazz, const char* name, const char* sig); // 非静态成员变量
jfieldID GetStaticFieldID(jclass clazz, const char* name, const char* sig); // 静态成员变量
示例:获取成员变量jfieldID方法
例如Student类中有String mName; int mAge;
,则获取成员变量jfieldID方法为:
jclass studentClass = env->FindClass("com/lmshao/jniexample/Student");
jfieldID nameField = env->GetFieldID(studentClass, "mName", "Ljava/lang/String;");
jfieldID ageField = env->GetFieldID(studentClass, "mAge", "I");
Set非静态成员变量
对成员变量操作的函数都与变量的类型相关,有一系列针对不同变量类型(XXX)的函数SetXXXField
可以使用,用法类似,使用时根据变量类型进行选择。
void SetObjectField(jobject obj, jfieldID fieldID, jobject value);
void SetBooleanField(jobject obj, jfieldID fieldID, jboolean value);
void SetByteField(jobject obj, jfieldID fieldID, jbyte value);
void SetCharField(jobject obj, jfieldID fieldID, jchar value);
void SetShortField(jobject obj, jfieldID fieldID, jshort value);
void SetIntField(jobject obj, jfieldID fieldID, jint value);
void SetLongField(jobject obj, jfieldID fieldID, jlong value);
void SetFloatField(jobject obj, jfieldID fieldID, jfloat value);
void SetDoubleField(jobject obj, jfieldID fieldID, jdouble value);
示例:非静态成员变量赋值
假设CourseScore类中有成员变量mMath,接下来对这个变量进行赋值操作。
jclass courseScoreClass = env->FindClass("com/lmshao/jniexample/CourseScore"); // get jclass
jfieldID mathField = env->GetFieldID(courseScoreClass, "mMath", "I"); // get jfield
jobject courseScoreObject = env->AllocObject(courseScoreClass); // get jobject
env->SetIntField(courseScoreObject, mathField, (jint)96); // set field
Get非静态成员变量
同样也是一系列针对不同变量类型(XXX)的函数GetXXXField
,用法类似,使用时根据变量类型进行选择。
jobject GetObjectField(jobject obj, jfieldID fieldID);
jboolean GetBooleanField(jobject obj, jfieldID fieldID);
jbyte GetByteField(jobject obj, jfieldID fieldID);
jchar GetCharField(jobject obj, jfieldID fieldID);
jshort GetShortField(jobject obj, jfieldID fieldID);
jint GetIntField(jobject obj, jfieldID fieldID);
jlong GetLongField(jobject obj, jfieldID fieldID);
jfloat GetFloatField(jobject obj, jfieldID fieldID);
jdouble GetDoubleField(jobject obj, jfieldID fieldID);
示例:获取非静态成员变量值
假设CourseScore类中有成员变量mMath,在已经得到jobject的情况下获取其中mMath变量的值。
// 已知 jobject courseScoreObject
jclass courseScoreClass = env->FindClass("com/lmshao/jniexample/CourseScore"); // get jclass
jfieldID mathField = env->GetFieldID(courseScoreClass, "mMath", "I"); // get jfield
jint score = env->GetIntField(courseScoreObject, mathField); // get field
Set静态成员变量
同样也是一系列针对不同变量类型(XXX)的函数SetStaticXXXField
,用法类似,使用时根据变量类型进行选择。注意:第一个参数为jclass,因为静态成员只属于类class,而不属于实例object。
void SetStaticObjectField(jclass clazz, jfieldID fieldID, jobject value);
void SetStaticBooleanField(jclass clazz, jfieldID fieldID, jboolean value);
void SetStaticByteField(jclass clazz, jfieldID fieldID, jbyte value);
void SetStaticCharField(jclass clazz, jfieldID fieldID, jchar value);
void SetStaticShortField(jclass clazz, jfieldID fieldID, jshort value);
void SetStaticIntField(jclass clazz, jfieldID fieldID, jint value);
void SetStaticLongField(jclass clazz, jfieldID fieldID, jlong value);
void SetStaticFloatField(jclass clazz, jfieldID fieldID, jfloat value);
void SetStaticDoubleField(jclass clazz, jfieldID fieldID, jdouble value);
Get静态成员变量
同样也是一系列针对不同变量类型(XXX)的函数GetStaticXXXField
,用法类似,使用时根据变量类型进行选择。注意:第一个参数为jclass,因为静态成员只属于类class,而不属于实例object。
jobject GetStaticObjectField(jclass clazz, jfieldID fieldID);
jboolean GetStaticBooleanField(jclass clazz, jfieldID fieldID);
jbyte GetStaticByteField(jclass clazz, jfieldID fieldID);
jchar GetStaticCharField(jclass clazz, jfieldID fieldID);
jshort GetStaticShortField(jclass clazz, jfieldID fieldID);
jint GetStaticIntField(jclass clazz, jfieldID fieldID);
jlong GetStaticLongField(jclass clazz, jfieldID fieldID);
jfloat GetStaticFloatField(jclass clazz, jfieldID fieldID);
jdouble GetStaticDoubleField(jclass clazz, jfieldID fieldID);
调用Java类的方法(成员函数)
获取Java类方法ID jmethodID
根据jclass可以使用GetMethodID
或GetStaticMethodID
函数获取方法ID(jmethodID)。参数1为jclass,参数2为方法名,参数3为方法的签名。
方法和变量签名可以使用命令javac Student.java
编译,然后使用命令javap -s -p Student.class
查看签名。
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig); // 非静态方法
jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig); //静态方法
示例:获取方法ID jmethodID
例如Student类中有void setName(String name); int getAge();
方法,接下来获取相应的jmethodID。
jclass studentClass = env->FindClass("com/lmshao/jniexample/Student");
jmethodID setnameMethod = env->GetMethodID(studentClass, "setName", "(Ljava/lang/String;)V");
jmethodID getageMethod = env->GetMethodID(studentClass, "getAge", "()I");
获取Java类静态方法ID与获取非静态方法ID的用法相同。
调用非静态方法
同样也是一系列针对不同变量类型(XXX)的函数GetXXXMethod
,用法类似,使用时根据变量类型进行选择。
jobject CallObjectMethod(jobject, jmethodID, ...);
jboolean CallBooleanMethod(jobject, jmethodID, ...);
jbyte CallByteMethod(jobject, jmethodID, ...);
jchar CallCharMethod(jobject, jmethodID, ...);
jshort CallShortMethod(jobject, jmethodID, ...);
jint CallIntMethod(jobject, jmethodID, ...);
jlong CallLongMethod(jobject, jmethodID, ...);
jfloat CallFloatMethod(jobject, jmethodID, ...);
jdouble CallDoubleMethod(jobject, jmethodID, ...);
void CallVoidMethod(jobject, jmethodID, ...);
示例:调用非静态方法
例如Student类中有void setAge();
方法,接下来调用这两个方法。
jclass studentClass = env->FindClass("com/lmshao/jniexample/Student");
jmethodID setageMethod = env->GetMethodID(studentClass, "setAge", "(I)V");
jobject studentObject = env->AllocObject(studentClass);
env->CallVoidMethod(studentObject, setageMethod, (jint)26); //没有返回值
调用静态方法
同样也是一系列针对不同变量类型(XXX)的函数GetStaticXXXMethod
,用法类似,使用时根据变量类型进行选择。
jobject CallStaticObjectMethod(jclass, jmethodID, ...);
jboolean CallStaticBooleanMethod(jclass, jmethodID, ...);
jbyte CallStaticByteMethod(jclass, jmethodID, ...);
jchar CallStaticCharMethod(jclass, jmethodID, ...);
jshort CallStaticShortMethod(jclass, jmethodID, ...);
jint CallStaticIntMethod(jclass, jmethodID, ...);
jlong CallStaticLongMethod(jclass, jmethodID, ...);
jfloat CallStaticFloatMethod(jclass, jmethodID, ...);
jdouble CallStaticDoubleMethod(jclass, jmethodID, ...);
void CallStaticVoidMethod(jclass, jmethodID, ...);
示例:调用静态方法
例如Student类中有static int getAge();
方法,接下来调用这两个方法。
jclass studentClass = env->FindClass("com/lmshao/jniexample/Student");
jmethodID getageMethod = env->GetStaticMethodID(studentClass, "getAge", "()I");
jint age = env->CallStaticIntMethod(studentClass, getageMethod);
相关文章
- 暂无相关文章
用户点评