轉載請註明出處:http://blog.csdn.net/xyang81/article/details/42066665java
JNI中的基本類型和Java中的基本類型都是一一對應的,接下來先看一下JNI的基本類型定義:編程
基本類型很容易理解,就是對C/C++中的基本類型用typedef從新定義了一個新的名字,在JNI中能夠直接訪問。 JNI把Java中的全部對象看成一個C指針傳遞到本地方法中,這個指針指向JVM中的內部數據結構,而內部的數據結構在內存中的存儲方式是不可見的。只能從JNIEnv指針指向的函數表中選擇合適的JNI函數來操做JVM中的數據結構。第三章的示例中,訪問java.lang.String對應的JNI類型jstring時,沒有像訪問基本數據類型同樣直接使用,由於它在Java是一個引用類型,因此在本地代碼中只能經過GetStringUTFChars這樣的JNI函數來訪問字符串的內容。安全
示例解析:數據結構
1> 訪問字符串函數
sayHello函數接收一個jstring類型的參數text,但jstring類型是指向JVM內部的一個字符串,和C風格的字符串類型char*不一樣,因此在JNI中不能通把jstring看成普通C字符串同樣來使用,必須使用合適的JNI函數來訪問JVM內部的字符串數據結構。編碼
GetStringUTFChars(env, j_str, &isCopy) 參數說明:spa
env:JNIEnv函數表指針.net
j_str:jstring類型(Java傳遞給本地代碼的字符串指針)指針
isCopy:取值JNI_TRUE和JNI_FALSE,若是值爲JNI_TRUE,表示返回JVM內部源字符串的一份拷貝,併爲新產生的字符串分配內存空間。若是值爲JNI_FALSE,表示返回JVM內部源字符串的指針,意味着能夠經過指針修改源字符串的內容,不推薦這麼作,由於這樣作就打破了Java字符串不能修改的規定。但咱們在開發當中,並不關心這個值是多少,一般狀況下這個參數填NULL便可。code
由於Java默認使用Unicode編碼,而C/C++默認使用UTF編碼,因此在本地代碼中操做字符串的時候,必須使用合適的JNI函數把jstring轉換成C風格的字符串。JNI支持字符串在Unicode和UTF-8兩種編碼之間轉換,GetStringUTFChars能夠把一個jstring指針(指向JVM內部的Unicode字符序列)轉換成一個UTF-8格式的C字符串。在上例中sayHello函數中咱們經過GetStringUTFChars正確取得了JVM內部的字符串內容。
2> 異常檢查
調用完GetStringUTFChars以後不要忘記安全檢查,由於JVM須要爲新誕生的字符串分配內存空間,當內存空間不夠分配的時候,會致使調用失敗,失敗後GetStringUTFChars會返回NULL,並拋出一個OutOfMemoryError異常。JNI的異常和Java中的異常處理流程是不同的,Java遇到異常若是沒有捕獲,程序會當即中止運行。而JNI遇到未決的異常不會改變程序的運行流程,也就是程序會繼續往下走,這樣後面針對這個字符串的全部操做都是很是危險的,所以,咱們須要用return語句跳事後面的代碼,並當即結束當前方法。
3> 釋放字符串
在調用GetStringUTFChars函數從JVM內部獲取一個字符串以後,JVM內部會分配一塊新的內存,用於存儲源字符串的拷貝,以便本地代碼訪問和修改。即然有內存分配,用完以後立刻釋放是一個編程的好習慣。經過調用ReleaseStringUTFChars函數通知JVM這塊內存已經不使用了,你能夠清除了。注意:這兩個函數是配對使用的,用了GetXXX就必須調用ReleaseXXX,並且這兩個函數的命名也有規律,除了前面的Get和Release以外,後面的都同樣。
4> 建立字符串
經過調用NewStringUTF函數,會構建一個新的java.lang.String字符串對象。這個新建立的字符串會自動轉換成Java支持的Unicode編碼。若是JVM不能爲構造java.lang.String分配足夠的內存,NewStringUTF會拋出一個OutOfMemoryError異常,並返回NULL。在這個例子中咱們沒必要檢查它的返回值,若是NewStringUTF建立java.lang.String失敗,OutOfMemoryError這個異常會被在Sample.main方法中拋出。若是NewStringUTF建立java.lang.String成功,則返回一個JNI引用,這個引用指向新建立的java.lang.String對象。