原文出處: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層代碼,需要進行以下步驟。
- 獲取Java層對應的
jclass
,通過jclass
來獲取Java類的方法,屬性。 - 獲取Java層對象引用,如果Java層有傳引用下來,則可用直接使用,否則就需要在C/C++層調用創建對象的接口來創建Java層對應類的對象。調用Java靜態函數不需要對象引用。
- 調用Java層類的靜態方法,或者Java層對象的方法。
- 處理返回值。
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 |