Jni理论知识讲解讲解内容Jni简介Jni设计概述Jni函数Jni类型和数据结构调用API函数1.简介Jni产生的背景什么是JniJava本地接口概述Java本地接口的方法利用Jni编程1.1jni产生的背景应用程序需要使用系统相关的功能,而Java代码不支持或是难以办到。已有其他语言写好的类库或程序,希望Java程序可以使用它们Java本地接口的方法出于更高的性能要求,希望使用汇编或是C/C++语言来实现部分功能1.2什么是JniJava本地接口(JavaNativeInterface,JNI)。JNI是本地编程接口。它使得在Java虚拟机(VM)内部运行的Java代码能够与用其它编程语言(如C、C++和汇编语言)编写的应用程序和库进行互操作从Java1.1开始,JavaNativeInterface(JNI)标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了JAVA通过JNI调用本地方法,而本地方法是以库文件的形式存放的(在WINDOWS平台上是DLL文件形式,在UNIX机器上是SO文件形式)。通过调用本地的库文件的内部方法,使JAVA可以实现和本地机器的紧密联系,调用系统级的各接口方法1.2Java本地接口概述调用java本地方法的时机标准Java类库不支持与平台相关的应用程序所需的功能已经拥有了一个用另一种语言编写的库,而又希望通过JNI使Java代码能够访问该库想用低级语言(如汇编语言)实现一小段时限代码通过用JNI编程,可以将本地方法用于创建、检查及更新Java对象(包括数组和字符串)。调用Java方法。捕获或抛出异常。加载类和获得类信息。执行运行时类型检查。现今部分已有本地方法接口:JDK1.0本地方法接口Netscape的Java运行时接口Microsoft的原始本地接口和Java/COM接口1.4目标标准接口能够向每个用户提供以下好处每个虚拟机厂商都可以支持更多的平台相关代码工具构造器不必维护不同的本地方法接口应用程序设计人员可以只编写一种版本的平台相关代码就能够在不同的虚拟机上运行标准本地方法接口必须满足以下要求二进制兼容性效率功能1.5利用JNI编程利用JNI编程隔离了一些未知条件遵守JNI标准是本地库能在给定Java虚拟机上运行的最好保证实现JNI能确保它不会占用虚拟机实现的系统开销或施加任何限制,包括对象表示,垃圾收集机制等2.Jni设计概述JNI接口函数和指针加载和链接本地方法引用Java对象访问Java对象报告编程错误异常2.1JNI接口函数和指针含义:JNI函数可通过接口指针来获得针是指针的指针,它指向一个指针数组,而指针数组中的每个元素又指向一个接口函数每个接口函数都处在数组的某个预定偏移量中虚拟机可支持以下两个JNI函数表:一个表对非法参数进行全面检查,适用于调试程序另一个表只进行JNI规范所要求的最小程度的检查,因此效率较高2.2加载和链接本地方法解析本地方法名前缀Java_mangled全限定的类名下划线(“_”)分隔符mangled方法名对于重载的本地方法,加上两个下划线(“__”),后跟mangled参数签名如:java_(包名)_class_method字符转换转义字符序列表示_0XXXXUnicode字符XXXX。_1字符“_”_2签名中的字符“;”_3签名中的字符“[”2.3本地方法的参数第一个参数:JNI接口指针第二个参数(非静态本地方法:对象的引用、静态本地方法:其Java类的引用)其余的参数对应于通常Java方法的参数定义本地方法:packagepkg;classCls{nativedoublef(inti,Strings);...}用C实现本地方法jdoubleJava_pkg_Cls_f__ILjava_lang_String_2(JNIEnv*env,/*接口指针*/jobjectobj,/*“this”指针*/jinti,/*第一个参数*/jstrings)/*第二个参数*/{/*取得Java字符串的C版本*/constchar*str=(*env)-GetStringUTFChars(env,s,0);/*处理该字符串*/.../*至此完成对str的处理*/(*env)-ReleaseStringUTFChars(env,s,str);return...}用C++实现本地方法externC/*指定C调用约定*/jdoubleJava_pkg_Cls_f__ILjava_lang_String_2(JNIEnv*env,/*接口指针*/jobjectobj,/*“this”指针*/jinti,/*第一个参数*/jstrings)/*第二个参数*/{constchar*str=env-GetStringUTFChars(s,0);...env-ReleaseStringUTFChars(s,str);return...}2.4引用Java对象局部引用:局部引用在本地方法调用期间有效,并在本地方法返回后被自动释放掉全局引用:将一直有效,直到被显式释放实现局部应用Java虚拟机为每个从Java到本地方法的控制转换都创建了注册服务程序2.5访问Java对象访问基本类型数组Jni提供了一套函数,用于在Java数组的一部分和本地内存缓冲之间复制基本类型数组元素程序员可用另一套函数来取回数组元素的受约束版本接口提供了一些函数,用以通知虚拟机本地方法已不再需要访问这些数组元素钉住:(1)垃圾收集器必须支持钉住(2)虚拟机必须在内存中连续存放基本类型数组访问域和方法保留对所涉及类的活引用重新计算该方法ID或域ID获得方法id的方法:jmethodIDmid=env-GetMethodID(cls,f“,(ILjava/lang/String;)D);重复调用的方法:jdoubleresult=env-CallDoubleMethod(obj,mid,10,str);2.6报告编程错误强迫JNI函数去检查所有可能的错误情况将降低正常(正确)的本地方法的性能在许多情况下,没有足够的运行时的类型信息可供这种检查使用JNI不检查诸如传递NULL指针或非法参数类型之类的编程错误2.7异常异常和错误代码快速检查上一个JNI调用所返回的值以确定是否出错通过调用函数ExceptionOccurred()来获得异常对象,它含有对错误情况的更详细说明调用Java方法的JNI函数返回该Java方法的结果。程序员必须调用ExceptionOccurred()以检查在执行Java方法期间可能发生的异常某些用于访问JNI数组的函数并不返回错误代码,但可能会抛出ArrayIndexOutOfBoundsException或ArrayStoreException异步异常(在多个线程的情况下,当前线程以外的其它线程可能会抛出异步异常)该平台相关代码调用某个有可能抛出同步异常的JNI函数该平台相关代码用ExceptionOccurred()显式检查同步异常或异步异常准备数据库的驱动程序异常的处理本地方法可选择立即返回,使异常在启动该本地方法调用的Java代码中抛出平台相关代码可通过调用ExceptionClear()来清除异常,然后执行自己的异常处理代码3.jni函数函数描述NeString利用Unicode字符数组构造新的java.lang.String对象GetStringLength返回Java字符串的长度(Unicode字符数)GetStringChars返回指向字符串的Unicode字符数组的指针。该指针在调用ReleaseStringchars()前一直有效ReleaseStringChars通知虚拟机平台相关代码无需再访问chars。参数chars是一个指针,可通过GetStringChars()从string获得NewStringUTF利用UTF-8字符数组构造新java.lang.String对象GetStringUTFLength以字节为单位返回字符串的UTF-8长度GetStringUTFChars返回指向字符串的UTF-8字符数组的指针。该数组在被ReleaseStringUTFChars()释放前将一直有效ReleaseStringUTFChars通知虚拟机平台相关代码无需再访问utf。utf参数是一个指针,可利用GetStringUTFChars()从string获得字符串函数数组函数函数描述GetArrayLength返回数组中的元素数NewObjectArray构造新的数组,它将保存类elementClass中的对象。所有元素初始值均设为initialElementGetObjectArrayElement返回Object数组的元素SetObjectArrayElement设置Object数组的元素异常检查函数异常检查函数(*env)-ExceptionCheck(env)用这个函数可以检查出来是否有异常,没有返回零返回发生的异常(*env)-ExceptionOccurred(env)返回的对象会占用一个引用打印调用堆栈(*env)-ExceptionDescribe(env)清空异常(*env)-ExceptionClear(env)4.JNI的类型和数据结构基本类型和本地等效类型Java类型本地类型说明booleanjboolean无符号,8位bytejbyte无符号,8位charjchar无符号,16位shortjshort有符号,16位intjint有符号,32位longjlong有符号,64位floatjfloat32位值类型jvalue联合类型在参数数组中用作单元类型。其声明方式如下:typedefunionjvalue{jbooleanz;jbyteb;jcharc;jshorts;jinti;jlongj;jfloatf;jdoubled;jobjectl;}jvalue;类型签名类型签名Java类型ZbooleanBbyteCcharSshortIintJLongFfloatLfully-qualified-class;全限定的类[typetype[](arg-types)ret-type方法类型2.10调用API函数函数名参数返回值JNI_GetDefaultJavaVMInitArgsvm_args(指向VM-specificnitialization(特定于虚拟机的初始化)结构的指针,缺省参数填入该结构)如果所请求的版本得到支持,则返回“0”;如果所请求的版本未得到支持,则返回负数JNI_GetCreatedJavaVMsvmBuf:指向将放置虚拟机结构的缓冲区的指针。bufLen:缓冲区的长度。nVMs:指向整数的指针成功时返回“0”;失败则返回负数JNI_CreateJavaVMp_vm:指向位置(其中放置所得到的虚拟机结构)的指针。p_env:指向位置(其中放置主线程的JNI接口指针)的指针。vm_args:Java虚拟机初始化参数成功时返回“0”;失败则返回负数DestroyJavaVMvm:将销毁的Java虚拟机成功时返回“0”;失败则返回负数AttachCurrentThreadvm:当前线程所要连接到的虚拟机。p_env:指向位置(其中放置当前线程的JNI接口指针)的指针。thr_args:特定于虚拟机的线程连接参数成功时返回“0”;失败则返回负数DetachCurrentThreadvm:当前线程将断开连接的虚拟机成功时返回“0”;失败则返回负数