JNI使用规范

1、  JNI概述

JavaNative Interface的缩写,中文为Java本地调用。从Java1.1开始,JNI即成为Java标准的一部分。 数组

JNI设计的目的是为了容许Java代码与其余语言进行交互。但这样作一般会致使丧失平台可移植性,一般是在特定的需求下进行,例如使用旧的其余语言的库、须要得到Java类库不支持的某种基于具体平台的特性、大量数学计算性能优化等。 缓存

2、  JNI数据类型和数据结构

1.基本类型 性能优化

JNI基本类型和本地等效类型的对应表格以下: 数据结构

  

Java类型 函数

  

本地类型 性能

说明 优化

boolean 编码

jboolean spa

无符号,8位 设计

byte

jbyte

无符号,8位

char

jchar

无符号,16位

short

jshort

有符号,16位

int

jint

有符号,32位

long

jlong

有符号,64位

float

jfloat

32位

double

jdouble

64位

void

void

为了使用方便,还提供了以下定义:

#define JNI_FALSE 0

#define JNI_TRUE 1

Jsize类型用于描述主要指数和大小:

typedef jint jsize;

    2.引用类型

除了基本类型外,JNI还包含了很对对应于不一样Java对象的引用类型,JNI引用类型的组织层次以下图所示:


在C语言中,全部其余JNI引用类型都被定义为与jobject同样,例如:

    typedef jobject jclass;

在C++中,JNI引入虚构类以增强子类关系,例如:

    class _jobject{};

    class _jstring : public jobject{};

    …

    typedef _jobject jobject;

    typedef _jstring jstring;

    3.方法ID和域ID

       方法ID和域ID是常规的C指针类型:

           struct_jmethodID;                     /*不透明结构*/

           typedefstruct _jmethodID *jmethodID;  /*方法ID*/

           struct_jfieldID;                      /*不透明结构*/

           typedefstruct _jfieldID *jfieldID     /*域ID*/

    4.值类型

       jvalue联合在参数数组中用做单元类型,其声明以下:

           typedefunion _jvalue

{

    jboolean z;

    jbyte b;

    jchar c;

    jshort s;

    jint i;

    jlong j;

    jfloat f;

    jdouble d;

    jobject l;

}jvalue;

    5.UTF8字符串

JNI的UTF8字符串与标准UTF8格式有两个区别,第一,空字节0使用双字节格式进行编码,而不是标准UTF8的单字节;第二,只使用单字节、双字节和三字节格式,不支持更长的字节格式。

3、  JNI接口函数命名方式

1. 类型签名

Java虚拟机的类型签名以下:

  

类型签名

  

Java类型

Z

boolean

B

byte

C

char

S

short

I

int

J

long

F

float

D

double

Lfully-qulitied-class;

全限定类

[type

type[] 数组

(argtypes)rettype

方法类型

例如,Java方法int feet(int n, String s,int [] arr)的类型签名以下:

(ILJava/lang/String;[I)I

圆括号里面为参数,I表示第一个参数int型,LJava/lang/String;表示第二个参数为全限定Java.lang.String类型,[I表示第三个参数为int型的数组,圆括号后面为返回值类型,I表示返回值为int型。

2. 通常函数的JNI接口函数命名方式

通常JNI接口函数命名以下:

    Java_包名_类名_方法名。

例如:某工程下Sample/test包下MySigal类的int GetASample()方法的C语言实现函数命名以下:

jint Java_Sample_test_MySigal_GetASample(JNIEnv* env,jobjectobj)

其中,包名所包含的“/”应所有如下划线替代,其本地实现的参数和返回值也应转换为JNI类型。

3. 重载函数的JNI接口函数命名方式

重载函数的JNI实如今通常函数的JNI实现以外,还应添加上类型签名以做为同名函数之间的区别,其接口函数命名以下:

    Java_包名_类名_方法名_参数签名。

例如:某工程下Sample/test包下MySigal类的int GetASample(int n, String s,int [] arr)方法的C语言实现函数命名以下:

jintJava_Sample_test_MySigal_GetASample_ILJava_lang_String_2_3I

(JNIEnv*env, jobject obj, jint n, jstring s, jintarray arr)。

JNI在函数命名时采用名字扰乱方案,以保证全部的Unicode字符都能转换为有效的C函数名,全部的“/”,不管是包名中的仍是全限定类名中的,均使用“_”代替,用_0,…,_9来代替转义字符,以下:

  

转义字符序列

  

表示

_0XXXX

Unicode字符XXXX

_1

字符“_”

_2

签名中的字符“;”

_3

签名中的字符“[”

4、  JNI函数与API

在目前的应用中,咱们所主要须要关心的是C/C++数据类型与JNI本地类型之间的转化过程,这个过程某些数据的转换须要使用JNIEnv对象的一系列方法来完成。

1.jstring转换为C风格字符串

char* test = (char*)(*env)->GetStringUTFChars(env,jstring,NULL);

使用完毕后,应调用:

(*env)->ReleaseStringUTFChars(env,jstring, test);

释放资源。

2.C风格字符串转换为jstring

char charStr[50];

jstring jstr;

jstr = env ->NewStringUTF(charStr);

3.C语言中获取的一段char*的buffer传递给Java

在jni中new一个byte数组,而后使用

(*env)->SetByteArrayRegion(env,bytearray, 0, len, buffer)

操做将buffer拷贝到数组中。

这种方式主要是针对buffer中存在“\0”的状况,若是以C风格字符串的方式读入,就会损失“\0”以后的字符。

4.数组操做

数组操做的相关函数列表以下:

  

JNI函数

  

功能

GetArrayLength

返回数组中的元素数

NewObjectArray

建立一个指定长度的原始数据类型数组

GetObjectArrayElement

返回Object数组的元素

SetObjectArrayElement

设置Object数组的元素

GetObjectArrayRegion

将原始数据类型数组中的内容拷贝到预先分配好的内存缓存中

SetObjectArrayRegion

设置缓存中数组的值

ReleaseObjectArrayRegion

释放GetObjectArrayRegion分配的内存


对int,char等基本数据类型的数组操做,将相关Object名称替换为对应基本数据类型名称即为相关函数。

数组操做的方法选择基于使用者的需求而定,若是使用者须要在内存中拷贝数组并对其进行操做那么通常使用GetObjectArrayRegion和SetObjectArrayRegion函数,不然通常使用SetObjectArrayElement和GetObjectArrayElement函数。

相关文章
相关标签/搜索