JNI(直接注册JNI本地函数)
JNI机制提供了名称为RegisterNatives()的JNI函数,该函数运行C/C++开发者将JNI本地函数与Java类的本地方法直接映射在一起。当不调用RegisterNatives()函数时,Java虚拟机会自动检索并将JNI本地函数与相应的Java本地方法链接在一起。但当开发者直接调用RegisterNatives()函数进行映射时,Java虚拟机就不必进行映射处理,这会极大提高运行速度,提高运行效率。
实例
HelloJNI.java
public class HelloJNI
{
//本地方法声明
native void printHello();
native void printString(String str);
//加载库
static { System.loadLibrary("hellojni"); }
public static void main(String[] args)
{
HelloJNI myJNI = new HelloJNI();
//调用本地方法(实际调用的是使用C语言编写的JNI本地函数)
myJNI.printHello();
myJNI.printString("Hello World from printString fun");
}
}
hellojnimap.cpp
#include "jni.h"
#include <stdio.h>
//JNI本地函数原型
void printHelloNative(JNIEnv *env,jobject obj);
void printStringNative(JNIEnv *env,jobject obj,jstring string);
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm,void *reserved)
{
JNIEnv* env = NULL;
JNINativeMethod nm[2];
jclass cls;
jint result = -1;
if(vm->GetEnv((void**) &env,JNI_VERSION_1_4) != JNI_OK)
{
printf("Error");
return JNI_ERR;
}
cls = env->FindClass("HelloJNI");
nm[0].name = (char *)"printHello";
nm[0].signature = (char *)"()V";
nm[0].fnPtr = (void *)printHelloNative;
nm[1].name = (char *)"printString";
nm[1].signature = (char *)"(Ljava/lang/String;)V";
nm[1].fnPtr = (void *)printStringNative;
env->RegisterNatives(cls,nm,2);
return JNI_VERSION_1_4;
}
//实现JNI本地函数
void printHelloNative(JNIEnv *env,jobject obj)
{
printf("Hello World!\n");
return;
}
void printStringNative(JNIEnv *env,jobject obj,jstring string)
{
const char *str = env->GetStringUTFChars(string,0);
printf("%s!\n",str);
return;
}
编译:
gcc -shared -o hellojni.dll hellojnimap.cpp
javac HelloJNI.java
运行:
java HelloJNI
结果:
Hello World!
Hello World from printString fun!
JNI_OnLoad()讲解
在加载指定库文件时,JNI_OnLoad()函数会被自动调用执行,程序开发者若想手工映射本地方法与JNI本地函数,需要在JNI_OnLoad()函数内调用RegisterNatives()函数进行映射匹配。
JNI_OnLoad()
形式:
jint JNI_OnLoad(JavaVM *vm,void *reserved)
说明:
Java虚拟机加载本地库时(System.loadLibrary()等方法被调用时)会调用JNI_OnLoad()函数。在使用加载库的过程中,JNI_OnLoad()函数会向Java虚拟机确认JNI的版本。若库中不包含JNI_OnLoad()函数,Java虚拟机会认为相关库要求JNI1.1版本支持参数:
- vm JavaVM接口指针
- reserved 预定参数
返回值:
若执行成功,则返回所生成的数组引用,若失败,则返回NULL
判断支持版本
GetEnv()
形式:
jnit GetEnv(JavaVM *vm,void **env,jint version)
说明:
判断Java虚拟机是否支持version指定的JNI版本,而后将JNI接口指针设置到*env中
参数:
- vm JavaVM接口指针的地址
- env JNI接口指针地址
- version JNI版本
返回值:
若执行成功,返回0,失败,返回负数
注册绑定
JNINativeMethod用来保存待映射的本地方法与JNI本地函数的相关信息
typedef struct {
char *name;//本地方法名称
char *signature;//本地方法签名
void *fnPtr;//与本地方法相对应的JNI本地函数指针
} JNINativeMethod
RegisterNatives()
形式:
jarray RegisterNatives(JNIEnv *env,jclass clazz,const JNINativeMethod *methods,jnit nMethods)
说明:
将clazz指定类中的本地方法与JNI本地函数链接在一起,链接信息保存在JNINativeMethod结构体数组中参数
- env JNI接口指针
- clazz Java类
- methods 包含本地方法与JNI本地函数的链接信息
- nMethods methods数组元素的个数
返回值
若执行成功,返回数组引用,否则,返回NULL