JNI使用規范

jopen 11年前發布 | 16K 次閱讀 JNI Java開發

一、  JNI概述

JavaNative Interface的縮寫,中文為Java本地調用。從Java1.1開始,JNI即成為Java標準的一部分。

JNI設計的目的是為了允許Java代碼與其他語言進行交互。但這樣做通常會導致喪失平臺可移植性,通常是在特定的需求下進行,例如使用舊的其他語言的庫、需要獲得Java類庫不支持的某種基于具體平臺的特性、大量數學計算性能優化等。

二、  JNI數據類型和數據結構

1.基本類型

JNI基本類型和本地等效類型的對應表格如下:

  

Java類型

  

本地類型

說明

boolean

jboolean

無符號,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的單字節;第二,只使用單字節、雙字節和三字節格式,不支持更長的字節格式。

三、  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

簽名中的字符“[”

四、  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 函數。

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!