JNI层调用java层,主要是通过反射机制找到class的成员变量和成员函数进行调用。
-
- //JNIEnv: JNIEnv是一份JNI环境,提供了大部分jni的接口,但是它是一个与线程相关的变量,不能保存为全局变量,需要时再从传入的env中调用
-
- //JavaVM;JavaVM是一份java虚拟机的实例,通过JNI_ONload函数传入,由于进程内共享,所以传入后即可保存为全局变量。JavaVM可以获取当前线程的env,调用方法为:JavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)
-
-
- /*
- * Class: HelloWorld
- * Method: sayhello
- * Signature: ()V
- */
- JNIEXPORT void JNICALL Dynamic_Java_HelloWorld_sayhello
- (JNIEnv *env, jobject thiz)
- {
- printf("jni say hello world\n");
-
- //GetObjectClass通过传入类对象参数,用于获取class对象,获取class对象的用处时用于反射机制找到成员变量或者成员函数
- jclass HelloWorldClazz=env->GetObjectClass(thiz);
-
- //GetFieldID通过传入class对象和成员变量变量名和变量类型,从而利用反射机制获取了得到成员变量的方法,不过限制时智能获取声明为public的成员变量或者成员方法。
- jfieldID num_id=env->GetFieldID(HelloWorldClazz,"num","I");
-
- //GetIntField通过反射返回一个实例的一个成员变量
- int num=env->GetIntField(thiz,num_id);
- printf("jni get num :[%d]\n",num);
- num = 886;
- printf("jni set num :[%d]\n",num);
-
- //SetIntField通过反射设置一个实例的一个成员变量
- env->SetIntField(thiz,num_id,num);
-
- //GetMethodID通过传入class对象和成员函数函数名和函数类型,
- jmethodID saybyebye_id=env->GetMethodID(HelloWorldClazz,"saybyebye","()V");
- printf("jni call byebye\n");
-
- //CallVoidMethod调用一个实例的无返回值方法
- env->CallVoidMethod(thiz,saybyebye_id);
-
- //一般情况new的变量需要delete
- env->DeleteLocalRef(HelloWorldClazz);
- }
修改HelloWorld.cpp
- #include <jni.h>
- #include <stdio.h>
- #include "HelloWorld.h"
-
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Class: HelloWorld
- * Method: sayhello
- * Signature: ()V
- */
- JNIEXPORT void JNICALL Dynamic_Java_HelloWorld_sayhello
- (JNIEnv *env, jobject thiz)
- {
- printf("jni say hello world\n");
-
- jclass HelloWorldClazz=env->GetObjectClass(thiz);
- jfieldID num_id=env->GetFieldID(HelloWorldClazz,"num","I");
- int num=env->GetIntField(thiz,num_id);
- printf("jni get num :[%d]\n",num);
- num = 886;
- printf("jni set num :[%d]\n",num);
- env->SetIntField(thiz,num_id,num);
-
- jmethodID saybyebye_id=env->GetMethodID(HelloWorldClazz,"saybyebye","()V");
- printf("jni call byebye\n");
- env->CallVoidMethod(thiz,saybyebye_id);
- env->DeleteLocalRef(HelloWorldClazz);
- }
-
-
- static JNINativeMethod gMethods[]=
- {
- {"sayhello","()V",(void*)Dynamic_Java_HelloWorld_sayhello}
- };
-
- jint JNI_OnLoad(JavaVM* vm,void* reserved)
- {
- JNIEnv *env=NULL;
- jint result =-1;
- if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK)
- {
- return -1;
- }
- char className[20]={"HelloWorld"};
- jclass clazz=env->FindClass((const char*)className);
- if(env->RegisterNatives(clazz,gMethods,1)<0)
- {
- return -1;
- }
-
- result=JNI_VERSION_1_4;
- printf("JNI_ONload\n");
- return result;
-
- }
-
- #ifdef __cplusplus
- }
- #endif
修改HelloWorld.java
- public class HelloWorld
- {
- static
- {
- System.loadLibrary("HelloWorld");
- }
-
- public int num = 0;
- public void saybyebye()
- {
- System.out.println("java saybyebye,num="+num);
- }
-
- public native void sayhello();
-
- public static void main(String[] args)
- {
- HelloWorld hw = new HelloWorld();
- System.out.println("call jni sayhello");
- hw.sayhello();
- }
- }
编译
- #编译java类
- javac HelloWorld.java
-
- #编译jni so库
- gcc HelloWorld.cpp --shared -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -fPIC
运行HelloWorld
- java HelloWorld
- #JNI_ONload
- #java call jni sayhello
- #jni say hello world
- #jni get num:[0]
- #jni set num:[886]
- #jni call byebye
- #java say byebye,num=886
可以看到jni层调用了java层HelloWorld类的saybyebye的成员函数,并且成员变量也发生了改变
jni调用java层是要反射机制调用。