JNI,是Java Native Interface的縮寫
· Java程序中的函數(shù)可以調(diào)用Native語言寫的函數(shù),Native一般指的是C/C++編寫的函數(shù)。
· Native程序中的函數(shù)可以調(diào)用Java層的函數(shù),也就是在C/C++程序中可以調(diào)用Java的函數(shù)。
java做的事
· 加載對應的JNI庫。
· 聲明由關(guān)鍵字native修飾的函數(shù)。
JNI做的事
. JNI層必須實現(xiàn)為動態(tài)庫的形式,這樣Java虛擬機才能加載它并調(diào)用它的函數(shù)。
. 注冊JNI函數(shù)--之意就是將Java層的native函數(shù)和JNI層對應的實現(xiàn)函數(shù)關(guān)聯(lián)起來
. 數(shù)據(jù)類型轉(zhuǎn)換
.JNIEnv通過調(diào)用CallVoidMethod,CallIntMethod等調(diào)用Java對象
一、注冊JNI函數(shù)
1、靜態(tài)注冊
· 先編寫Java代碼,然后編譯生成.class文件。
· 使用Java的工具程序javah,如javah–o output packagename.classname ,這樣它會生成一個叫output.h 的JNI層頭文件。其中packagename.classname是Java代碼編譯后的class文件,而在生成的output.h文件里,聲明了對應的JNI層函數(shù),只要實現(xiàn)里面的函數(shù)即可。
關(guān)聯(lián)關(guān)系,其實就是保存JNI層函數(shù)的函數(shù)指針。以后再調(diào)用native_init函數(shù)時,直接使用這個函數(shù)指針就可以了,當然這項工作是由虛擬機完成的。
2、動態(tài)注冊
動態(tài)注冊的工作,只用兩個函數(shù)就能完成
.jclass clazz = (env)->FindClass(env, className);
. //調(diào)用JNIEnv的RegisterNatives函數(shù),注冊關(guān)聯(lián)關(guān)系。
(env)->RegisterNatives(env, clazz, gMethods,numMethods);
當Java層通過System.loadLibrary加載完JNI動態(tài)庫后,緊接著會查找該庫中一個叫JNI_OnLoad的函數(shù),如果有,就調(diào)用它,而動態(tài)注冊的工作就是在這里完成的。
二、數(shù)據(jù)類型轉(zhuǎn)換
在Java中調(diào)用native函數(shù)傳遞的參數(shù)是Java數(shù)據(jù)類型,那么這些參數(shù)類型到了JNI層會變成什么呢?
Java數(shù)據(jù)類型分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型兩種
三、JNIEnv介紹
JNIEnv實際上就是提供了一些JNI系統(tǒng)函數(shù)。通過這些函數(shù)可以做到:
· 調(diào)用Java的函數(shù)。
· 操作jobject對象等很多事情。
1、jfieldID 和jmethodID的介紹
在JNI規(guī)則中用jfieldID 和jmethodID 來表示Java類的成員變量和成員函數(shù)通過JNIEnv的下面兩個函數(shù)可以得到:
jfieldID GetFieldID(jclass clazz,const char*name, const char sig);
jmethodID GetMethodID(jclass clazz, const charname,const char *sig);
2、使用jfieldID和jmethodID
JNIEnv通過調(diào)用CallVoidMethod,CallIntMethod、CallStatic等再把jobject、jMethodID和對應參數(shù)傳進去,JNI層就能夠調(diào)用Java對象的函數(shù)了