1. 程式人生 > >NDK開發 從入門到放棄(四:JNI函式、C與C++呼叫函式的區別)

NDK開發 從入門到放棄(四:JNI函式、C與C++呼叫函式的區別)

前言

在之前的文章中我們看到過如下C++程式碼:

jclass clazz = env->FindClass("***/***/JNIDynamicUtils");

FindClass就屬於jni函式。此文就來稍微講解下一些常用的jni函式。

C與C++呼叫函式的區別

如上述程式碼,則是C++檔案內的程式碼。標準的C實現上述程式碼的方式是:

jclass clazz = (*env)->FindClass(env, "***/***/JNIDynamicUtils");

看到不同的表示方式便能知道寫的是C還是C++了。相比較的話,C++程式碼還是簡潔一些。

JNI函式

以下為部分入門級函式,後續會不斷補充。

1. FindClass

jclass FindClass(JNIEnv *env, const char *name);

該函式用於載入本地定義的類。

引數:
env:JNI介面指標。下面將不再介紹 ,在C++程式碼中,引數不傳該值。
name:類全名(即包名後跟類名,之間由“/”分隔)。如果該名稱以“[”(陣列簽名字元)打頭,則返回一個數組類。

返回值:
返回類物件全名。如果找不到該類,則返回NULL。

丟擲:
ClassFormatError:如果類資料指定的類無效。
ClassCircularityError:如果類或介面是自身的超類或超介面。
NoClassDefFoundError:如果找不到所請求的類或介面的定義。
OutOfMemoryError:如果系統記憶體不足。

2. GetMethodID

jmethodID GetMethodID(JNIEnv *env, jclass clazz, const char *name, const char *sig);

返回類或介面例項(非靜態)方法的方法ID。方法可在某個clazz的超類中定義,也可從clazz繼承。該方法由其名稱和簽名決定。GetMethodID()可使未初始化的類初始化。要獲得建構函式的方法ID,應將<init>作為方法名,同時將()V作為返回型別。

引數:
clazz:Java類物件。
name:0終結的UTF-8字串中的方法名。
sig:0終結的UTF-8字串中的方法簽名。

返回值:
方法ID,如果找不到指定的方法,則為NULL。

丟擲:
NoSuchMethodError:如果找不到指定方法。
ExceptionInInitializerError:如果由於異常而導致類初始化程式失敗。
OutOfMemoryError:如果系統記憶體不足。

3. NewObject

jobject NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...);

構造新Java物件。方法ID必須通過呼叫GetMethodID()獲得,為應呼叫的建構函式方法。clazz引數務必不要引用陣列類。

引數:
clazz:Java類物件。
methodID:建構函式的方法ID。
其它引數:傳給建構函式的引數。

返回值:
返回Java物件,如果無法構造該物件,則返回NULL。

丟擲:
InstantiationException:如果該類為介面或抽象類。
OutOfMemoryError:如果系統記憶體不足。
其他:建構函式丟擲的任何異常。

4. NewStringUTF

jstring NewStringUTF(JNIEnv *env, const char *bytes);

利用UTF-8字元陣列構造新java.lang.String物件。

引數:
bytes:指向UTF-8字串的指標。

返回值:
Java字串物件。如果無法構造該字串,則為NULL。

丟擲:
OutOfMemoryError:如果系統記憶體不足。

5. GetStringUTFLength

jsize GetStringUTFLength(JNIEnv *env, jstring string);

以位元組為單位返回字串的UTF-8長度。

引數:
string:Java字串物件。

返回值:
返回字串的UTF-8長度。若引數為null,則會異常。

6. Throw

jint Throw(JNIEnv *env, jthrowable obj);

丟擲java.lang.Throwable異常物件。

引數:
obj:java.lang.Throwable物件。

返回值:
成功時返回0,失敗時返回負數。

丟擲:
java.lang.Throwable物件obj。

tip:
與java不同,丟擲異常後,後續程式碼還會繼續執行,直至return。

7. ThrowNew

jint ThrowNew(JNIEnv *env, jclass clazz, const char *message);

利用指定類的訊息(由message指定)構造異常物件並丟擲該異常。

引數:
clazz:java.lang.Throwable的子類。
message:用於構造java.lang.Throwable物件的訊息。

返回值:
成功時返回0,失敗時返回負數。

丟擲:
新構造的java.lang.Throwable物件。

8. GetArrayElements

 NativeType *Get<PrimitiveType>ArrayElements (JNIEnv *env, ArrayType array, jboolean*isCopy); 

一組返回基本型別陣列體的函式。結果在呼叫相應的ReleaseArrayElements()函式前將一直有效。由於返回的陣列可能是Java陣列的副本,因此對返回陣列的更改不必在基本型別陣列中反映出來,直到呼叫了 ReleaseArrayElements()。如果isCopy不是NULL,*isCopy在複製完成後即被設為JNI_TRUE。如果未複製,則設為JNI_FALSE。

GetArrayElements例程 陣列型別 本地型別
GetBooleanArrayElements() jbooleanArray jboolean
GetByteArrayElements() jbyteArray jbyte
GetCharArrayElements() jcharArray jchar
GetShortArrayElements() jshortArray jshort
GetIntArrayElements() jintArray jint
GetLongArrayElements() jlongArray jlong
GetFloatArrayElements() jfloatArray jfloat
GetDoubleArrayElements() jdoubleArray jdouble

引數:
array:Java字串物件。
isCopy:指向布林值的指標。

返回值:
返回指向陣列元素的指標,如果操作失敗,則為NULL。

9. ReleaseArrayElements

void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);

通知虛擬機器平臺相關程式碼無需再訪問elems的一組函式。elems引數是一個通過使用對應的GetArrayElements()函式由array匯出的指標。必要時,該函式將把對elems的修改複製回基本型別陣列。mode引數將提供有關如何釋放陣列緩衝區的資訊。 如果elems不是array中陣列元素的副本,mode將無效。否則,mode將具有下表所述的功能:

基本型別陣列釋放模 動作
0 複製回內容並釋放elems緩衝區
JNI_COMMIT 複製回內容但不釋放elems緩衝區
JNI_ABORT 釋放緩衝區但不復制回變化

多數情況下,程式設計人員將把“0”傳給mode引數以確保固定的陣列和複製的陣列保持一致。其它選項可以使程式設計人員進一步控制記憶體 管理,但使用時務必慎重。

引數:
array:Java陣列物件。
elems:指向陣列元素的指標。
mode:釋放模式。

10. NewArray

ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);

用於構造新基本型別陣列物件的一系列操作。下表說明了特定的基本型別陣列建構函式。使用者應把NewArray替換為 某個實際的基本型別陣列建構函式例程名(見下表),然後將ArrayType替換為該例程相應的陣列型別。

NewArray例程 陣列型別
NewBooleanArray() jbooleanArray
NewByteArray() jbyteArray
NewCharArray() jcharArray
NewShortArray() jshortArray
NewIntArray() jintArray
NewLongArray() jlongArray
NewFloatArray() jfloatArray
NewDoubleArray() jdoubleArray

引數:
length:陣列長度。

返回值:
Java陣列。如果無法構造該陣列,則為NULL。

11. SetArrayRegion

void Set<PrimitiveType>ArrayRegion(JNIEnv *env, ArrayType array, jsize start, jsize len, NativeType *buf);

將基本型別陣列的某一區域從緩衝區中複製回來的一組函式。下表說明了特定的基本型別陣列元素訪問器。應進行如下替換:

SetArrayRegion例程 陣列型別 本地型別
SetBooleanArrayRegion() jbooleanArray jboolean
SetByteArrayRegion() jbyteArray jbyte
SetCharArrayRegion() jcharArray jchar
SetShortArrayRegion() jshortArray jshort
SetIntArrayRegion() jintArray jint
SetLongArrayRegion() jlongArray jlong
SetFloatArrayRegion() jfloatArray jfloat
SetDoubleArrayRegion() jdoubleArray jdouble

引數:
array: Java陣列。
start:起始下標。
len:要複製的元素數。
buf:源緩衝區。

丟擲:
ArrayIndexOutOfBoundsException:如果區域中的某個下標無效。