Android中關於JNI 的學習(一)對於JNIEnv的一些認識

來源:互聯網
上載者:User

標籤:android   jnienv   jni   

一個簡單的例子讓我們初步地瞭解JNI的作用,但是關於JNI中的一些概念還是需要瞭解清楚,才能夠更好的去利用它來實現我們想要做的事情。

那麼C++和Java之間的是如何通過JNI來進行互相調用的呢?

我們知道,在Android中,當Java檔案被編譯成dex檔案之後,會由類載入器載入到Dalvik VM(DVM)中,由DVM來進行解釋,翻譯成機器語言之後,才能由機器來運行。

而對於C/C++來說,其原始碼經由Android提供的NDK工具包,可以編譯成可執行動態庫(即.so檔案),之後,Java和C++之間就可以進行通訊了。

那麼,在這裡,可以想像,Java的Dex位元組碼和C/C++的so庫肯定是同時運行在一個DVM之中,它們是共同使用一個進程空間的,否則,它們怎麼彼此溝通呢?

所以在這裡,一個關鍵的中間地區就是Dalvik VM。而對於C/C++,當它們也被載入進DVM之後,由C/C++實現的函數方法等都會被載入在DVM中的函數表中。

如果想要在C/C++中調用函數,它們必須要有個東西能夠讓其訪問到這個虛擬機器中的函數表。

而這個東西就是JNIEnv *。

當我們利用javah產生的C/C++的標頭檔的時候,如下:

JNIEXPORT jstring JNICALL Java_com_lms_jni_HwDemo_printHello  (JNIEnv *e, jobject j){        return (**e).NewStringUTF(e,"Hello from T" );}

我們可以看到這個方法有兩個參數,其中第一個就是JNIEnv *,而我們在Java端定義這個方法的時候,是沒有參數的,如下:

public native String printHello();

那麼這個JNIEnv是幹什麼用的?其實從這個參數的名稱就可以看到,就是指JNI的運行環境,我覺得它就是對Java虛擬環境的一個引用,在Android中,就是指Dalvik VM。參考jni.h檔案中關於JNIEnv的定義,如下(對於C和C++,它的定義有點不一樣):
struct _JNIEnv;struct _JavaVM;typedef const struct JNINativeInterface* C_JNIEnv;#if defined(__cplusplus)typedef _JNIEnv JNIEnv; //C++中JNIEnv的類型typedef _JavaVM JavaVM; #elsetypedef const struct JNINativeInterface* JNIEnv; //C中JNIEnv的類型typedef const struct JNIInvokeInterface* JavaVM;#endif

在C中,我們可以看到JNIEnv的類型就是JNINativeInterface* ,是一個指標類型,那麼在C++中呢,_JNIEnv是什麼樣的呢?
struct _JNIEnv {    /* do not rename this; it does not seem to be entirely opaque */    const struct JNINativeInterface* functions;

而對於C++來說, _JNIEnv是一個結構體,裡麵包含了JNINativeInterface*的結構。所以從這裡也可以看到,對於C和C++來說,它們引用JNIEnv中的方法是有一點不一樣的。總的來說,JNIEnv,不管是C,還是C++,其實關鍵都是JNINativeInterface的這個結構。我們可以簡單看一下JNINativeInterface結構的定義,如下:
struct JNINativeInterface {    void*       reserved0;    void*       reserved1;    void*       reserved2;    void*       reserved3;    jint        (*GetVersion)(JNIEnv *);    jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,                        jsize);    jclass      (*FindClass)(JNIEnv*, const char*);    jmethodID   (*FromReflectedMethod)(JNIEnv*, jobject);    jfieldID    (*FromReflectedField)(JNIEnv*, jobject);    /* spec doesn‘t show jboolean parameter */    jobject     (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);

可以看到在它其中定義了很多的函數指標,而通過這些定義,JNI層其實就獲得了對DVM的引用,通過定義的這些函數指標,可以定位到虛擬機器中的 JNI 函數表,從而實現JNI層在DVM中的函數調用。
所以,可以這樣理解,其實JNIEnv,就是對DVM運行環境中C/C++函數的一個引用,而也正因為此,當C/C++想要在DVM中調用函數的時候,由於其是在DVM的環境中,所以它們必須通過JNIEnv* 這個參數來獲得這些方法,之後才能夠使用。
那麼這個JNIEnv是什麼時候產生的呢?
當Android中第一個Java線程要調用本地的C/C++代碼的時候,DVM就會為該線程產生一個JNIEnv*的指標。而每一個線程在和C/C++互相調用的時候,其對應的JNIEnv 也是相互獨立。

嗯,結束。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.