Android JNI開發詳解(6)-對象操作

原文出處:http://www.ccbu.cc/index.php/android/android-jni-object-operate.html

1. 對象操作基本步驟

Jni是溝通Java世界和Native世界的紐帶,Java層調用本地方法只用調用Java中定義的本地(native)方法就可用了,那麼,本地的C/C++代碼如何調用Java層的代碼呢?這就是本章節對象操作要解決闡述的內容。

一般的,C/C++層要調用Java層代碼,需要進行以下步驟。

  1. 獲取Java層對應的jclass,通過jclass來獲取Java類的方法,屬性。
  2. 獲取Java層對象引用,如果Java層有傳引用下來,則可用直接使用,否則就需要在C/C++層調用創建對象的接口來創建Java層對應類的對象。調用Java靜態函數不需要對象引用。
  3. 調用Java層類的靜態方法,或者Java層對象的方法。
  4. 處理返回值。

2. 類操作

2.1 函數列表

Jni中類操作相關的函數包括以下函數:

函數 說明
DefineClass 從原始類數據的緩衝區中加載類
FindClass 查找類
GetSuperclass 查找父類
IsAssignableFrom 類型判斷

2.2 關於類名

Jni在加載或查找Java層類時,需要通過類的全名來進行加載,該類的全名爲類包含包名的全路徑,比如 java.lang.String類,那麼類的全名則爲java/lang/String

2.3 對應的C++函數定義如下:

/**
 * 從原始類數據的緩衝區中加載類
 * @param name 類的全名,必須是被UTF-8編碼過的字符串。
 * @param loader 類加載器
 * @param buf 包含 .class 文件數據的緩衝區
 * @return java類對象。發生錯誤時返回NULL
 */
jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
        jsize bufLen)

/**
 *  查找類
 * @param name 類的全名,必須是被UTF-8編碼過的字符串。
 * @return 
 */
jclass FindClass(const char* name)

/**
 * 獲取父類
 * @param clazz Java類對象
 * @return java類對象。clazz的父類或NULL
 */
jclass GetSuperclass(jclass clazz)

/**
 * 確定clazz1的對象是否可安全地強制轉換爲clazz2
 * @param clazz1 類的對象
 * @param clazz2 類的對象
 * @return 如果滿足以下任一條件,則返回JNI_TRUE:
 *         1. 如果clazz1和clazz2是同一個Java類。 
 *         2. 如果clazz1是clazz2的子類
 *         3. 如果clazz1是clazz2接口的實現類
 */
jboolean IsAssignableFrom(jclass clazz1, jclass clazz2)

2.4 對應的C函數定義爲:

jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*, jsize);
jclass      (*FindClass)(JNIEnv*, const char*);
jclass      (*GetSuperclass)(JNIEnv*, jclass);
jboolean    (*IsAssignableFrom)(JNIEnv*, jclass, jclass);
jclass      (*GetObjectClass)(JNIEnv*, jobject);

3. 對象操作

Jni中對象操作相關的函數主要包括:

函數 說明
AllocObject 直接創建Java對象
NewObject 根據某個構造函數來創建Java對象
NewObjectV 根據某個構造函數來創建Java對象
NewObjectA 根據某個構造函數來創建Java對象
GetObjectClass 獲取指定類對象的類
IsInstanceOf 判斷某個對象是否是某個“類”的子類

對應的C++函數定義如下:

/**
 * 不借助任何構造函數的情況下分配一個新的Java對象
 * @param clazz Java類對象
 * @return 返回一個Java對象實例,如果該對象無法被創建,則返回NULL
 */
jobject AllocObject(jclass clazz)

/**
 * 根據構造函數來創建Java對象
 * @param clazz Java類對象
 * @param methodID 構造函數的方法ID
 * @param ... 構造函數的輸入參數(可變參數)
 * @return 返回一個Java對象實例,如果無法創建該對象,則返回NULL
 */
jobject NewObject(jclass clazz, jmethodID methodID, ...)

/**
 * 根據構造函數來創建Java對象
 * @param clazz Java類對象
 * @param methodID 構造函數的方法ID
 * @param args 構造函數的輸入參數(va_list)
 * @return 返回一個Java對象實例,如果無法創建該對象,則返回NULL
 */
jobject NewObjectV(jclass clazz, jmethodID methodID, va_list args)

/**
 * 根據構造函數來創建Java對象
 * @param clazz Java類對象
 * @param methodID 構造函數的方法ID
 * @param args 構造函數的輸入參數(參數數組)
 * @return 返回一個Java對象實例,如果無法創建該對象,則返回NULL
 */
jobject NewObjectA(jclass clazz, jmethodID methodID, const jvalue* args)

/**
 * 通過對象獲取類
 * @param obj 類的對象
 * @return Java 類對象。
 */
jclass GetObjectClass(jobject obj)

/**
 * 判斷某個對象是否是某個“類”的子類
 * @param obj Java對象實例
 * @param clazz Java類對象
 * @return 
 */
jboolean IsInstanceOf(jobject obj, jclass clazz)

對應的C函數定義爲:

jobject     (*AllocObject)(JNIEnv*, jclass);
jobject     (*NewObject)(JNIEnv*, jclass, jmethodID, ...);
jobject     (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);
jobject     (*NewObjectA)(JNIEnv*, jclass, jmethodID, const jvalue*);
jclass      (*GetObjectClass)(JNIEnv*, jobject);
jboolean    (*IsInstanceOf)(JNIEnv*, jobject, jclass);

4. 獲取方法

本地C/C++代碼中,可用同類對象jclass來獲取該Java類的方法,主要包括獲取類方法和獲取靜態方法。

函數 說明
GetMethodID 獲取類方法
GetStaticMethodID 獲取類的靜態方法

對應的C++函數定義如下:

/**
 * 獲取指定類的類方法
 * @param clazz Java類對象
 * @param name 方法名,必須爲"utf-8"的字符串
 * @param sig 方法簽名,必須爲"utf-8"的字符串
 * @return 返回對應的方法ID,沒有找到指定的方法,則返回NULL
 */
jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)

/**
 * 獲取指定類的靜態方法
 * @param clazz Java類對象
 * @param name 方法名,必須爲"utf-8"的字符串
 * @param sig 方法簽名,必須爲"utf-8"的字符串
 * @return 返回對應的方法ID,沒有找到指定的方法,則返回NULL
 */
jmethodID GetStaticMethodID(jclass clazz, const char* name, const char* sig)

對應的C函數定義爲:

jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
jmethodID   (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);

5. 類方法調用

Jni中本地函數中回調Java類方法通過調用CallMethod系列函數實現。CallMethod系列函數,根據傳入參數的部分,分爲CallMethod, CallMethodV和CallMethodA三類函數,參數區別如下:

函數 參數類型 參數說明
getMethod 可邊長參數
getMethodV va_list va_list類型參數
getMethodA const jvalue* 數組形式的參數

以CallObjectMethod函數爲列,看一下其函數原型。

// C 函數原型
jobject     (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject     (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject     (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, const jvalue*);
// C++ 函數原型
jobject     CallObjectMethod(jobject, jmethodID, ...);
jobject     CallObjectMethodV(jobject, jmethodID, va_list);
jobject     CallObjectMethodA(jobject, jmethodID, const jvalue*);

類方法調用的CallMethod函數主要根據返回值類型的不同進行了分類,主要包括Object類型返回值的函數調用和基本數據類型返回值的函數調用。函數列表如下:

函數 返回值類型
CallObjectMethod
CallObjectMethodV
CallObjectMethodA
jobject
CallBooleanMethod
CallBooleanMethodV
CallBooleanMethodA
jboolean
CallByteMethod
CallByteMethodV
CallByteMethodA
jbyte
CallCharMethod
CallCharMethodV
CallCharMethodA
jchar
CallShortMethod
CallShortMethodV
CallShortMethodA
jshort
CallIntMethod
CallIntMethodV
CallIntMethodA
jint
CallLongMethod
CallLongMethodV
CallLongMethodA
jlong
CallFloatMethod
CallFloatMethodV
CallFloatMethodA
jfloat
CallDoubleMethod
CallDoubleMethodV
CallDoubleMethodA
jdouble
CallVoidMethod
CallVoidMethodV
CallVoidMethodA
void

6.類的靜態方法調用

Jni中本地函數中回調Java類的靜態方法的方式和訪問類方法的類似。唯一不同的是,調用類的靜態方法時不用傳入Java類對象引用。CallStaticMethod系列函數列表如下:

函數 返回值類型
CallObjectStaticMethod
CallObjectStaticMethodV
CallObjectStaticMethodA
jobject
CallBooleanStaticMethod
CallBooleanStaticMethodV
CallBooleanStaticMethodA
jboolean
CallByteStaticMethod
CallByteStaticMethodV
CallByteStaticMethodA
jbyte
CallCharStaticMethod
CallCharStaticMethodV
CallCharStaticMethodA
jchar
CallShortStaticMethod
CallShortStaticMethodV
CallShortStaticMethodA
jshort
CallIntStaticMethod
CallIntStaticMethodV
CallIntStaticMethodA
jint
CallLongStaticMethod
CallLongStaticMethodV
CallLongStaticMethodA
jlong
CallFloatStaticMethod
CallFloatStaticMethodV
CallFloatStaticMethodA
jfloat
CallDoubleStaticMethod
CallDoubleStaticMethodV
CallDoubleStaticMethodA
jdouble
CallVoidStaticMethod
CallVoidStaticMethodV
CallVoidStaticMethodA
void
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章