一、JNI调用java层基本方法
二、JNI调用java层步骤
1.关键函数和基本步骤
2.HelloWorld示例
总结
JNI层调用java层,主要是通过反射机制找到class的成员变量和成员函数进行调用。
//JNIEnv: JNIEnv是一份JNI环境,提供了大部分jni的接口,但是它是一个与线程相关的变量,不能保存为全局变量,需要时再从传入的env中调用
//JavaVM;JavaVM是一份java虚拟机的实例,通过JNI_ONload函数传入,由于进程内共享,所以传入后即可保存为全局变量。JavaVM可以获取当前线程的env,调用方法为:JavaVM->GetEnv(reinterpret_cast(&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
#include
#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层是要反射机制调用。