主题:
● 获取Java类
● 访问Java属性
●访问Java方法
●创建Java对象
●抛异常
1. 获取Java类
方法一:
jclass clazz = env->GetObjectClass(thisObj);
方法二:
jclass cls = env->FindClass("com/lht/JNITest");
以上方法是先获取到Class对象,当然这是c++的写法,c的写法是不一定的,我是喜欢用c++的方式来实现JNI
2. 读写Java属性
以后是用到的JNI 函数
jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID);
jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID);
jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID);
jchar (*GetCharField)(JNIEnv*, jobject, jfieldID);
jshort (*GetShortField)(JNIEnv*, jobject, jfieldID);
jint (*GetIntField)(JNIEnv*, jobject, jfieldID);
jlong (*GetLongField)(JNIEnv*, jobject, jfieldID);
jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID);
jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID);
void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);
void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);
void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);
void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);
void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);
void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);
void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat);
void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);
我们先看一下
jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);//这个方法相当的耗时,请不要频繁的使用,当读到以后应该保存起来
JNIEnv*就不用说了,jclass是要访问属性的类的class对象,如何获取已在上一节讲述了,第三个参数为属性名称,如你定义了一个String mName;那么参数为"mName",
第四个参数是属性的签名,mName的类型为String,那么它的签名应该是指"Ljava/lang/String;"
所以我们代码写成:jfieldID nameId = env->GetFieldID(class, "mName", "Ljava/lang/String;")
拿到nameId我们再来看看
jString name = (jString)env->GetObjectField(jObj, nameId);
jObj是java调用传入的this对象。
如果属性域是静态的,那么方法为GetStaticFieldID, GetStaticObjectField
获取完了以后,我们要设置呢?
env->SetObjectField(jObj, nameId, name); //第三个参数为值
3. 访问Java方法
根读写java属性的步骤一致。
先获取方法的ID
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
jclass, 就是要访问的类的类对象,是需要根据本篇的第一节的描述获取的jclass对象
name, 方法名称
sig, 方法的签名,如:“(Ljava/lang/String;I)V”
CallVoidMethod(jclass clazz,, methodID, ...);
CallVoidMethod(jclass clazz,, methodID, jvalue args[]);
CallVoidMethod(jclass clazz,, methodID, va_list args);
... , 用来传递参数,这个相信在Java中用的比较的多,如println类,你可以在后面跟很多个参数,如jString,jint and so on.
jvalue是一个枚举类:
typedef union jvalue {
jboolean z;
jbyte b;
jchar c;
jshort s;
jint i;
jlong j;
jfloat f;
jdouble d;
jobject l;
} jvalue;
va_list,是c语言中用来解决变参的宏,
后面两个调用方法不用管,一般我们用第一个就够了。
调用静态的方法:
跟上面的没有什么区别,只是分别用GetStaticMethodID和CallStaticVoidMethod方法
CallStaticObjectMethod(class, methodid, env->newStringUTF("java.class.path"))
4. 在JNI中创建Java类对象
jobject NewObject(jclass clazz, jmethodID methodID, ...)
参数说明:
clazz, java类
jmethodID, 构造函数ID
..., 构造参数
5. 抛异常
有两个接口可以实现
jint (*Throw)(JNIEnv*, jthrowable);
jint (*ThrowNew)(JNIEnv *, jclass, const char *);
6. 创建Java虚拟机
在非JNI的代码中,我们可以通过创建一个Java虚拟机来访问Java类
JavaVMOption options[1];
JavaVMInitArgs vm_args;
JavaVM *jvm;
JNIEnv *env;
options[0].optionString = "-Djava.class.path=.";
memset(&vm_args, 0, sizeof(vm_args));
vm_args.version = JNI_VERSION_1_4;
vm_args.nOption = 1;
vm_args.options = options;
JNI_CreateJavaVM(&jvm, (void**) & env, &vm_args);