JNI的簡單介紹
Java Native Interface (JNI)是java本地調(diào)用接口,所謂的native就是調(diào)用c/c++的程序。
java調(diào)用C語言的情況一般有三種:
從程序的角度來說,主要關(guān)注兩種情況:
對于理解JNI的調(diào)用實(shí)現(xiàn),對于理解Android的源碼有幫助,因?yàn)锳ndroid系統(tǒng)中大量的使用了JIN。
Java訪問C
任何語言直接的交互都必須遵循一定的規(guī)則或者協(xié)議,只有這樣雙方才能理解各自的意圖。
java中定義native函數(shù),對于native函數(shù)只需要聲明,具體實(shí)現(xiàn)由C去實(shí)現(xiàn)。也就是說,native函數(shù)的
實(shí)現(xiàn)與聲明是分離的,java負(fù)責(zé)聲明,C負(fù)責(zé)實(shí)現(xiàn)。所以java在編譯是不會(huì)關(guān)心具體實(shí)現(xiàn),編譯時(shí)就不會(huì)出錯(cuò)。
如何調(diào)用的呢?在調(diào)用之前java是不會(huì)關(guān)心是否已經(jīng)實(shí)現(xiàn),只有在調(diào)用native方法的時(shí)候,去找C生成的動(dòng)態(tài)庫,如果
找不到動(dòng)態(tài)庫,那么native方法就會(huì)報(bào)錯(cuò)。
java如何找到C的函數(shù)的呢?
java的native函數(shù)和C中的函數(shù)存在一種映射關(guān)系,這個(gè)映射關(guān)系就是遵循的一種協(xié)議或者稱為規(guī)則。
比如,F(xiàn)ramework中AssetManager類中聲明了:
private native final void init()
該方法在C中對應(yīng)的是:
static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
從上面的對應(yīng)關(guān)系可以看出,在C中的規(guī)則就是,包名+類名+方法名,并且中間用下劃線分割
第一個(gè)參數(shù)env,是JNIEnv對象,該對象代表一個(gè)Java虛擬機(jī)所運(yùn)行的環(huán)境,通過它可以訪問JVM內(nèi)部的各種對象;
第二個(gè)參數(shù)jobject和是調(diào)用該函數(shù)的對象,上面的例子指的就是AssetManager對象;每個(gè)這樣的C函數(shù)的參數(shù)至少
有這兩個(gè)參數(shù),如果native函數(shù)里有多個(gè)參數(shù),依次在后面排列,java的數(shù)據(jù)類型和JNI中的數(shù)據(jù)類型對應(yīng)關(guān)系,
自己可以去網(wǎng)上查詢一下。
當(dāng)java調(diào)用native函數(shù)時(shí),編譯器會(huì)向native引擎?zhèn)鬟f調(diào)用者的包名,函數(shù)名及參數(shù)類型,native引擎
根據(jù)這些信息決定應(yīng)該調(diào)用具體的的哪個(gè)函數(shù)。
在android中,native引擎中的AndroidRuntime類提供了一個(gè)registerNativeMethods()函數(shù),通過此函數(shù)
定義java方法和C函數(shù)的映射關(guān)系。
生成 .h文件
java 的native方法和JNI中的c中的函數(shù)的對應(yīng)的定義文件頭文件(.h文件)可以手工寫,有些麻煩
并且還容易出錯(cuò),java提供了一個(gè)javah工具,通過該工具可以從一個(gè)java文件自動(dòng)生成相應(yīng)的
投文件,網(wǎng)上查詢一下具體用法。
接下來就是根據(jù)頭文件去實(shí)現(xiàn)相應(yīng)的C代碼,然后生成動(dòng)態(tài)庫。
如果想在java中調(diào)用native方法,需要使用在調(diào)用的代碼前面使用System.loadLibrary("lib_name")去
裝載該動(dòng)態(tài)庫。
C訪問java
雖然C訪問java的情況不多見,不過也是能遇到的。
由于java中的函數(shù)在native引擎中并沒有直接的函數(shù)指針,java函數(shù)只能由java引擎去執(zhí)行,而不是C。所以訪問
java不能通過指針,只能通過參數(shù)接口。
java訪問c的時(shí)候,把類名,函數(shù)名,參數(shù)類型傳遞給native引擎,然后由native引擎處理C函數(shù),同理,
C調(diào)用java時(shí),也需要把想要訪問的類名、函數(shù)名、參數(shù)傳遞給java引擎。
按照如下步驟:
上面是調(diào)用方法,調(diào)用java的變量也類似:
在C中使用持久對象和保持持久對象
C中本身無法保存持久對象,把持久對象保存到一個(gè)int類型的變量上,使用的時(shí)候再強(qiáng)制轉(zhuǎn)型成對象。
|
|