您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > android JNI介绍
1Java基础之理解JNI原理目前Java与Dll交互的技术主要有三种:JNI、JAWIN和JACOB,JNI(JavaNativeInterface)是SUN提供的Java与系统中的原生方法的技术。JACOB(Java-ComBridge)提供Java程序调用Microsoft的com队形的方法能力,而除了com对象外,JAWIN(JAVA/WIN32integrationproject)还可以Win32-DLL动态链接库中的方法。即JNIJAWINJACOB.JVM封装了各种操作系统实际的差异性的同时,提供了JNI技术,使得开发者可以通过JAVA程序调用到操作系统相关的技术实现的库函数,从而与其他技术和系统交互,使用其他技术实现的系统的功能,同时其他技术和系统也可以通过JNI提供的相应原生接口调用JAVA应用系统内部实现的功能。1.1JNI调用过程JNI对于应用本身来说,可以看做一个代理模式,对于开始者来说,需要使用C/C++来实现一个代理程序来实际操作目标原生函数,Java程序中则是JVM通过加载并调用JNI程序间接地调用目标原生函数。其调用的示意图如下:Java程序开发的一般操作步骤如下:编写JAVA中的调用类;用javah生成C/C++原生函数的头文件;C/C++中调用需要的其他函数功能,实现原生函数;将项目依赖的所有原生库和资源加到java项目的java.library.path;生成JAVA程序;发布JAVA应用和DLL库;1.2JNI语法JNI对于应用本身来说,可以看做一个代理模式,对于开始者来说,需要使用C/C++来实现一个代理程序来实际操作目标原生函1.2.1数据类型转换基本数据类型转换表:JavaNative类型符号属性字长booleanjboolean无符号8位bytejbyte无符号8位charjchar无符号16位shortjshort有符号16位intjint有符号32位longjlong有符号64位floatjfloat有符号32位doublejdouble有符号64位备注:符号属性是指在JNI环境下。引用数据类型的转换:Java引用类型Native类型Java引用类型Native类型Allobjectjobjectchar[]jcharArrayjava.lang.class实例jclassshort[]jshortArrayjava.lang.String实例jstringint[]jintArrayobject[]jobjectArrayshort[]jshortArrayboolean[]jbooleanArraylong[]jlongArraybyte[]jbyteArraydouble[]jdoubleArrayjava.lang.Throwable实例jthrowablefloat[]jfloatArray1.2.2注册JNI函数JNI命名规则:JNI层需要将JAVA函数名称(包括包名)中的“.”换成“_”,用这种方式可以找到自己JNI层的本家兄弟。注册native函数有两种方法:静态注册和动态注册。静态注册方法:根据函数名找到对应的JNI函数,需要java的工具程序javah参与,其流程:(1)编写java代码,然后编译生成.class文件(2)使用java的工具程序javah,如javah–ooutputpackagename.这样会产生一个output.h的JNI层头文件,其中packagename.classname是java代码编译后class文件。以百度输入法的内核PlumCore.java为例,该类的全路径为com.baidu.input.PlumCore.java因此,执行的步骤:首先打开控制台(cmd),将当前的目录切换至工程的bin\classes目录下,执行javah-classpathE:\dev\base2\basehand\bin\classes-jnicom.baidu.input.PlumCore或者执行:javah-classpath.-jnicom.baidu.input.PlumCore。-classpath:表示编译后的class路径;-jni:指定需要导出的类名Java层调用函数时,会从对应的JNI中寻找该函数,如果没有就会报错,如果存在则会建立一个关联联系,以后在调用时会直接使用这个函数,这部分的操作由虚拟机完成。静态方法就是根据函数名来简历java和jni函数之间的关联,而且要求jni层函数的名字必须遵循特定的格式,其缺点在于:需要编译所有的java声明的类;javah生成的jni层函数特别长;初次调用native函数时要根据名字搜索对应的jni层函数来建立关联联系,这样影响效率。动态注册方法:Javanative与JNI通过JNINativeMethod的结构来建立联系,其结构内容如下:Typedefstruce{Constchar*name;//java中native函数的名字,不用携带包的路径Constchar*signature;//java函数的签名信息,用字符串表示,是参数类型和返回值类型的组合Void*fnptr;//JNI层对应的函数指针,注意他是void*的类型。}JNINativeMethod;AndroidRunTime提供一个RegisterNatives(JNIEnv*envConstchar*className,//类名全路径ConstJNINativeMethod*gMethods,//需要注册函数的实体intnumMethods)//注册函数个数JNIEXPORTjintJNI_OnLoad(JavaVM*vm,void*reserved){JNIEnv*env;if(vm-GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK){//fprintf(stderr,ERROR:GetEnvfailed\n);}jclassclazz;//等到plumecore类clazz=env-FindClass(com/baidu/input/PlumCore);if(clazz!=NULL)//进行注册env-RegisterNatives(clazz,method_table,sizeof(method_table)/sizeof(JNINativeMethod));return(JNI_VERSION_1_4);}JNIEXPORTvoidJNI_OnUnload(JavaVM*vm,void*reserved){JNIEnv*env;jclassk;jintr;r=vm-GetEnv((void**)&env,JNI_VERSION_1_2);k=env-FindClass(com/baidu/input/PlumCore);env-UnregisterNatives(k);}当java通过System.loadLibrary加载完JNI动态库后,紧接着会查找一个JNI_OnLoad的函数,如果有,就调用它,而动态注册的工作就是在这里完成的。1.2.3垃圾回收Java中创建的对象最后由垃圾回收器来回收和释放内存的,而对于JNI,直接对对象进行引用后不会增加引用计数值,当从JNI返回后在JNI引用的对象有可能被垃圾回收器回收,而在JNI下面记录的指针有可能是野指针,为了解决此类问题,JNI规范提供如下三类引用:(1)LocalRefrence:本地引用,在JNI层函数中使用的非全局变量都是采用LocalRefrence,它包含函数调用时传入的jobject和在JNI层函数中创建的jobject,其最大的特点是一旦JNI层函数返回,这些jobject就可能被垃圾回收了。(2)GlobalRefrence:全局引用,这类引用如果程序不主动调用销毁接口将一直驻留在内存中。(3)WeakGlobalRefrence:弱全局引用,在使用过程中有可能被释放,调用JNIEnv中IsSameObject函数来判断是否仍然存在。1.2.4JNI异常1.2.5JNINativeMethodTypedefstruce{Constchar*name;//java中native函数的名字,不用携带包的路径Constchar*signature;//java函数的签名信息,用字符串表示,是参数类型和返回值类型的组合Void*fnptr;//JNI层对应的函数指针,注意他是void*的类型。}JNINativeMethod;signature的书写规则如下:()中的字符表示参数,后面的则代表返回值,如“()V”就表示voidFunc(),“(II)V”表示voidFunc(int,int)等。具体的每个字符对应关系如下:字符java类型C类型VvoidvoidZjbooleanbooleanIjintintJjlonglongDjdoubledoubleFjfloatfloatBjbytebyteCjcharcharSjshortshort数组则以“[”开始,用两个字符表示[IjintArrayint[][FjfloatArrayfloat[][DjdoubleArraydouble[][ZjbooleanArrayboolean[][BjbyteArraybyte[][CjcharArraychar[][SjshortArrayshort[][JjlongArraylong[]如果java函数的参数是class,则以“L”开头,以“;”结尾,中间是用“/”隔开的包及类名,对应的C函数名的参数则为jobject,一个例外是String类,其对应类为jstring。Ljava/lang/String;StringjstringLjava/net/Socket;Socketjobject例如:JNI:JNIEXPORTjbooleanJNICALLJava_com_baidu_input_PlumCore_PlInit(JNIEnv*env,jobjectobj,jobjectArraynames,jobjectpackageInfo)签名内容:{PlInit,([Ljava/lang/String;Landroid/content/pm/PackageInfo;)Z,(void*)Java_com_baidu_input_PlumCore_PlInit},Java:protectednativebooleanPlInit(String[]fileNames,PackageInfopi);又如:JNI:JNIEXPORTjbooleanJNICALLJava_com_baidu_input_PlumCore_PlConfig(JNIEnv*env,jobjectobj,jbyteArrayconfigArray,jintconfigType)签名内容:{PlConfig,([BI)Z,(void*)Java_com_baidu_input_PlumCore_PlConfig},JAVA:publicnativebooleanPlConfig(byte[]params,inttype);1.3JNIEnv自变量相关接口JNIEnv自变量只想类型为JNIEnv的一个特殊JNI数据结构的指针,JNI数据结构的一个元素是指向由JVM生成的一个数组的指针;该数组的每个元素都是指向一个JNI函数的指针,可从固有方法的内容发出对JNI函数的调用。利用JNIEnv自变量,程序员可访问一系列函数。这些函数可划分为下述类别:■获取版本信息■进行类和对象操作■控制对Java对象的全局和局部引用■访问实例字段和静态字段■调用实例方法和静态方法■执行字串和数组操作■产生和控制Java异常1.3.1字符串操作jstringNewString(JNIEnv*env,constjchar*unicodeChars,jsizelen);利用Unicode字符数组构造新的java.lang.Strin
本文标题:android JNI介绍
链接地址:https://www.777doc.com/doc-3601189 .html