JavaNative Interface的縮寫,中文爲Java本地調用。從Java1.1開始,JNI即成爲Java標準的一部分。 數組
JNI設計的目的是爲了容許Java代碼與其餘語言進行交互。但這樣作一般會致使喪失平臺可移植性,一般是在特定的需求下進行,例如使用舊的其餘語言的庫、須要得到Java類庫不支持的某種基於具體平臺的特性、大量數學計算性能優化等。 緩存
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的單字節;第二,只使用單字節、雙字節和三字節格式,不支持更長的字節格式。
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 |
簽名中的字符「[」 |
在目前的應用中,咱們所主要須要關心的是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函數。