Android JNI開發摘錄(三)之JNI中的Java對象

四 JNI中的Java對象

   Java本機接口提供了一個函數集來處理Java對象(使用方法/域)、句柄異常和用於線程的數據同步。這些函數在本機提供更好的訪問Java對象的能力,允許用於更復雜的應用程序。這些函數的用法之一是被用來產生一個Java方法的回調,或者產生通信信息的回調。

    1.訪問JNI中的域

    在Java類中有兩種成員變量類型:靜態域,它們屬於類;非靜態域,它們屬於單個對象。爲了可以訪問一個域,必須向GetFieldID或GetStatiieldID傳遞一個域描述符以及域的名稱。域描述符是完整描述域類型的一個或多個字符。例如,域int的域描述符是I。用於數組的域描述符是以字符 [ 爲前綴,用於數組的每一維。例如,int[]的域描述符是[I,int[][]的域描述符是[[I。對於引用類型,使用了類的完整限制符名稱,但是點號被正斜槓替換,描述符將在開始被一個L,在結尾被一個分號所包圍。例如,類型java.lang.Integer的域描述符是Ljava/lang/Integer。基本類型域描述符如下表:

基本類型   域描述符  

boolean   Z  

byte   B  

char   C  

short   S  

int   I  

long   J  

float   F  

double   D  

2.訪問域的函數

      (1).下面的函數向指定域返回一個句柄,以便用於Get以及Set函數。GetObjectClass函數可以用來獲取一個適合於該函數第一個參數的jclass。name是域的名稱,sig是域描述符。如果函數失敗,返回NULL:

jfieldID GetFieldID(jclass clazz, constchar *name, constchar *sig);


     (2).下面的函數返回屬於Java對象obj的,被fieldID指定的一個特定域:

[NativeType] Get[Type]Field(jobject obj, jfieldID fieldID);


    (3).SetField函數將屬於Java對象obj的,被fieldID指定的一個特定域的值設置爲val:

void Set[Type]Field(jobject obj,jfieldID fieldID, [NativeType] val);


   (4)GetStatiieldID函數同GetFieldID函數功能相同,但它用於獲取一個靜態域的句柄:

jfieldID GetStatiieldID(jclass clazz,constchar *name, constchar *sig);



   (5)GetStatiield函數返回屬於clazz描述的類,fieldID指定的一個靜態域的值:

[NativeType] GetStatic[Type]Field(jclass clazz,jfieldID fieldID);



   (6).SetStatiield函數設置屬於clazz描述的類,fieldID指定一個靜態域的值:

void SetStatic[Type]Field(jclass clazz, jfieldID fieldID, [NativeType] value);

   3.使用JNI調用Java方法

   使用JNI可以調用Java中的靜態及非靜態方法,這時需要使用方法的名稱和方法描述符來獲得特定Java方法的句柄,然後才能通過CallMethod函數調用該Java方法。

   方法描述符通過將所有方法的參數類型放置到一個單一圓括號集中,然後在圓括號之後指定返回類型而形成。用於參數的類型以及返回類型使用在前面描述過的域描述符。如果方法返回void,則描述符就是V。若方法沒有任何參數,則圓括號中爲空。用於熟悉的main方法的方法描述符是([Ljava/lang/String;)V。如果希望調用構造函數,使用方法名<init>,對於靜態構造函數,則使用<clinit>。

 JNI調用Java方法的步驟:

    獲取方法和變量描述符的編譯命令:javap -s -classpath . [PacketName+"."+Library Name]  如:javap -s -classpath . com.example.MyProject.MyLibrary

   (1).獲取要調用方法所在的類:

jclass GetObjectClass(jobject obj);

  (2).通過jclass獲取要調用的方法的methodID,即方法句柄:

/**

*使用步驟(1)獲取的jclass

*方法名稱

*方法描述符

*/

jmethod GetMethodID(jclass clazz,constchar *name,constchar *sig);

jmethod GetStaticMethodID(jclass clazz,constchar* name,constchar *sig);


   (3).通過方法句柄調用方法,注意:如果希望調用一個構造函數或一個私有方法,方法ID將會基於實際對象的類獲得,而不是基於對象的一個超類。


/**

*java環境傳入的jobject

*方法句柄

*/參數:接受大量參數,並將這些參數直接傳送到Java方法中

[NativeType] Call[Type]Method(jobject obj, jmethodID methodID,…);

/**

*該方法將參數列表作爲一個va_list結構接受,該結構是隨同參數列

*表預包裝的。

*/

[NativeType] Call[Type]MethodV(jobject obj,jmethodID methodID,va_list args);

/**

*該方法將參數作爲一個jvalue數組接受,它是可以使用任意本機數據*類型版本的Java數據類型形式的一個聯合(union),包括jobject。

*/

[NativeType] Call[Type]MethodA(jobject obj, jmethodID methodID, const jvalue *args);



/**

*下面三個方法也調用對象方法的一個實例,但是調用的Java方法是

*基於jclass數的。這些函數可以在對象的層次結構中調用一個指定的方法,而不是僅僅基於對象的類調用一個方法。

*jclass應通過傳入要調用的方法所在的類的實例來獲得。

*/

[NativeType] CallNonvirtual[Type]Method(jobject obj, jclass clazz, jmethodID methodID, …);



[NativeType]  CallNonvirtual[Type]MethodV(jobject obj, jclass clazz, jmethodID methodID, va_list args);



[NativeType]  CallNonvirtual[Type]MethodA(jobject obj, jclass clazz, jmethodID methodID, const jvalue *args);





/**

*下面的函數調用屬於傳入的clazz類的一個靜態方法。使用Get

*StaticMethodID來獲得方法句柄。

*/

[NativeType] CallStatic[Type]Method(jclass clazz, jmethodID methodID, …);



[NativeType]  CallStatic[Type]MethodV(jclass clazz, jmethodID methodID, va_list args);



[NativeType]  CallStatic[Type]MethodA(jclass clazz, jmethodID methodID, const jvalue *args);


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章