JNI查漏补缺(3)JNI调用java层

目录

一、JNI调用java层基本方法

二、JNI调用java层步骤

1.关键函数和基本步骤

2.HelloWorld示例

总结


一、JNI调用java层基本方法

JNI层调用java层,主要是通过反射机制找到class的成员变量和成员函数进行调用。

二、JNI调用java层步骤

1.关键函数和基本步骤


//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);
}

2.HelloWorld示例

修改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层是要反射机制调用。

你可能感兴趣的:(基础查漏补缺,java,开发语言)