如何使用JNI的一些基本方法和过程在网上多如牛毛,若是你对Jni不甚了解,不知道Jni是作什么的,如何创建一个基本的jni程序,或许能够参考下面下面这些文章:
利用VC++6.0实现JNI的最简单的例子
JNI入门教程之HelloWorld篇
SUN JNI Tutorial
这些资料的例子中,大多数只是输入一些简单的参数,获取没有参数。而在实际的使用过程当中,每每须要对参数进行处理转换。才能够被C/C++程序识别。好比咱们在C++中有一个结构(Struct)DiskInfo ,须要传递一个相似于DiskInfo *pDiskInfo的参数,相似于在C++这样参数如何传递到Java中呢?下面咱们就来讨论C++到Java中方法的一些常见参数的转换:
html
若是你习惯了使用JNI,你就不会以为它难了。既然本地方法是由其余语言实现的,它们在Java中没有函数体。可是,全部本地代码必须用本地关键词声明,成为Java类的成员。假设咱们在C++中有这么一个结构,它用来描述硬盘信息: java
那么咱们须要在Java中定义一个类来与之匹配,声明能够写成这样: web
在这个类中,申明一些Native的本地方法,来测试方法参数的传递,分别定义了一些函数,用来传递结构或者结构数组,具体定义以下面代码: windows
编译生成C/C++头文件
定义好了Java类以后,接下来就要写本地代码。本地方法符号提供一个知足约定的头文件,使用Java工具Javah能够很容易地建立它而不用手动去建立。你对Java的class文件使用javah命令,就会为你生成一个对应的C/C++头文件。
一、在控制台下进入工做路径,本工程路径为:E:\work\java\workspace\JavaJni。
二、运行javah 命令:javah -classpath E:\work\java\workspace\JavaJni com.sundy.jnidemo ChangeMethodFromJni
本文生成的C/C++头文件名为: com_sundy_jnidemo_ChangeMethodFromJni.h
在C/C++中实现本地方法
生成C/C++头文件以后,你就须要写头文件对应的本地方法。注意:全部的本地方法的第一个参数都是指向JNIEnv结构的。这个结构是用来调用JNI函数的。第二个参数jclass的意义,要看方法是否是静态的(static)或者实例(Instance)的。前者,jclass表明一个类对象的引用,然后者是被调用的方法所属对象的引用。 数组
返回值和参数类型根据等价约定映射到本地C/C++类型,如表JNI类型映射所示。有些类型,在本地代码中可直接使用,而其余类型只有经过JNI调用操做。 eclipse
表A jvm
Java类型 | 本地类型 | 描述 |
boolean | jboolean | C/C++8位整型 |
byte | jbyte | C/C++带符号的8位整型 |
char | jchar | C/C++无符号的16位整型 |
short | jshort | C/C++带符号的16位整型 |
int | jint | C/C++带符号的32位整型 |
long | jlong | C/C++带符号的64位整型e |
float | jfloat | C/C++32位浮点型 |
double | jdouble | C/C++64位浮点型 |
Object | jobject | 任何Java对象,或者没有对应java类型的对象 |
Class | jclass | Class对象 |
String | jstring | 字符串对象 |
Object[] | jobjectArray | 任何对象的数组 |
boolean[] | jbooleanArray | 布尔型数组 |
byte[] | jbyteArray | 比特型数组 |
char[] | jcharArray | 字符型数组 |
short[] | jshortArray | 短整型数组 |
int[] | jintArray | 整型数组 |
long[] | jlongArray | 长整型数组 |
float[] | jfloatArray | 浮点型数组 |
double[] | jdoubleArray | 双浮点型数组 |
※ JNI类型映射
ide
JNI经过JNIEnv提供的操做Java数组的功能。它提供了两个函数:一个是操做java的简单型数组的,另外一个是操做对象类型数组的。 函数
由于速度的缘由,简单类型的数组做为指向本地类型的指针暴露给本地代码。所以,它们能做为常规的数组存取。这个指针是指向实际的Java数组或者Java数组的拷贝的指针。另外,数组的布置保证匹配本地类型。 工具
为了存取Java简单类型的数组,你就要要使用GetXXXArrayElements函数(见表B),XXX表明了数组的类型。这个函数把Java数组当作参数,返回一个指向对应的本地类型的数组的指针。
表B
函数 | Java数组类型 | 本地类型 |
GetBooleanArrayElements | jbooleanArray | jboolean |
GetByteArrayElements | jbyteArray | jbyte |
GetCharArrayElements | jcharArray | jchar |
GetShortArrayElements | jshortArray | jshort |
GetIntArrayElements | jintArray | jint |
GetLongArrayElements | jlongArray | jlong |
GetFloatArrayElements | jfloatArray | jfloat |
GetDoubleArrayElements | jdoubleArray | jdouble |
JNI数组存取函数
当你对数组的存取完成后,要确保调用相应的ReleaseXXXArrayElements函数,参数是对应Java数组和GetXXXArrayElements返回的指针。若是必要的话,这个释放函数会复制你作的任何变化(这样它们就反射到java数组),而后释放全部相关的资源。
为了使用java对象的数组,你必须使用GetObjectArrayElement函数和SetObjectArrayElement函数,分别去get,set数组的元素。GetArrayLength函数会返回数组的长度。
JNI提供的另一个功能是在本地代码中使用Java对象。经过使用合适的JNI函数,你能够建立Java对象,get、set 静态(static)和实例(instance)的域,调用静态(static)和实例(instance)函数。JNI经过ID识别域和方法,一个域或方法的ID是任何处理域和方法的函数的必须参数。
表C列出了用以获得静态(static)和实例(instance)的域与方法的JNI函数。每一个函数接受(做为参数)域或方法的类,它们的名称,符号和它们对应返回的jfieldID或jmethodID。
表C
函数 | 描述 |
GetFieldID | 获得一个实例的域的ID |
GetStaticFieldID | 获得一个静态的域的ID |
GetMethodID | 获得一个实例的方法的ID |
GetStaticMethodID | 获得一个静态方法的ID |
※域和方法的函数
若是你有了一个类的实例,它就能够经过方法GetObjectClass获得,或者若是你没有这个类的实例,能够经过FindClass获得。符号是从域的类型或者方法的参数,返回值获得字符串,如表D所示。
表D
Java 类型 | 符号 |
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | L |
float | F |
double | D |
void | V |
objects对象 | Lfully-qualified-class-name;L类名 |
Arrays数组 | [array-type [数组类型 |
methods方法 | (argument-types)return-type(参数类型)返回类型 |
※肯定域和方法的符号