訪問成員變量
無論是實例變量還是靜態(tài)變量琉兜,分三個步驟:
- 獲取類。表示需要訪問哪一個java類,如所在jni方法對應(yīng)java實例方法,參數(shù)中有jobject對象善涨,則需要通過GetObjectClass得到類;如所在jni方法對應(yīng)java靜態(tài)方法草则,參數(shù)中已有jclass對象钢拧。
- 獲取域ID。表示要訪問類中的哪個變量炕横。
- 獲取域值源内。即獲取變量的值。
示例:java類中有實例變量和靜態(tài)變量
public class MainActivity extends AppCompatActivity {
private String instanceField = "instace";
private static String staticField = "static field";
...
}
jni中獲取時份殿,GetFieldID方法的第二個參數(shù)為變量的名稱膜钓,第三個參數(shù)為變量的簽名描述符(見下文)
extern "C" JNIEXPORT void JNICALL
Java_smarttime_tsia_com_jnitest3_MainActivity_stringFromJNI(JNIEnv* env, jobject obj) {
// 獲取類
jclass clazz = env->GetObjectClass(obj);
// 獲取實例變量ID
jfieldID instanceFieldId = env->GetFieldID(clazz, "instanceField", "Ljava/lang/String;");
// 獲取實例變量值
jstring instanceValue = static_cast<jstring>(env->GetObjectField(obj, instanceFieldId));
// 獲取靜態(tài)變量ID
jfieldID staticField = env->GetStaticFieldID(clazz, "staticField", "Ljava/lang/String;");
// 獲取靜態(tài)變量值
jstring staticValue = static_cast<jstring>(env->GetStaticObjectField(clazz, staticField));
...
}
- 若域ID頻繁使用,可以緩存下來以提高程序性能卿嘲。
- 原生代碼方位java變量需要調(diào)用兩到三個jni函數(shù)呻此,給程序增加了額外的負(fù)擔(dān),導(dǎo)致性能的下降腔寡。一般情況下,建議將所有需要的參數(shù)傳遞給原生方法調(diào)用掌唾。
訪問成員方法
分三個步驟:
- 獲取類放前。表示需要訪問哪一個java類,如所在jni方法對應(yīng)java實例方法糯彬,參數(shù)中有jobject對象凭语,則需要通過GetObjectClass得到類;如所在jni方法對應(yīng)java靜態(tài)方法撩扒,參數(shù)中已有jclass對象似扔。
- 獲取方法ID吨些。表示要訪問類中的哪個方法
- 調(diào)用方法。
示例:java類中有實例方法和靜態(tài)方法
public class MainActivity extends AppCompatActivity {
...
private String instanceMethod() {
return "instance method";
}
private static String staticMethod() {
return "static method";
}
...
現(xiàn)在jni中調(diào)用炒辉,并獲得其返回值豪墅,GetMethodID第二個參數(shù)為方法名稱,第三個參數(shù)為方法的簽名描述符(見下文)
extern "C" JNIEXPORT void JNICALL
Java_smarttime_tsia_com_jnitest3_MainActivity_stringFromJNI3(JNIEnv* env, jobject obj) {
// 獲取類
jclass clazz = env->GetObjectClass(obj);
// 獲取實例方法ID
jmethodID instancemethodId = env->GetMethodID(clazz, "instanceMethod", "()Ljava/lang/String;");
// 調(diào)用實例方法
jstring instanceRet = static_cast<jstring>(env->CallObjectMethod(obj, instancemethodId));
// 獲取靜態(tài)方法ID
jmethodID staticmethodId = env->GetStaticMethodID(clazz, "staticMethod", "()Ljava/lang/String;");
// 調(diào)用靜態(tài)方法
jstring staticRet = static_cast<jstring>(env->CallStaticObjectMethod(clazz, staticmethodId));
...
}
- 若方法ID頻繁使用黔寇,可以緩存下來以提高程序性能偶器。
- java和原生代碼之間的轉(zhuǎn)換代價較大,程序設(shè)計上要最小化在原生代碼調(diào)用java方法缝裤,以提高程序的性能屏轰。
簽名描述符
上文中使用到的簽名描述符用來標(biāo)識能標(biāo)識變量的類型、方法的參數(shù)和返回值憋飞,獲取描述符有兩種方式:
命令生成方式
javap是JDK提供的命令行方式下java類文件的反編譯程序霎苗,它可以從編譯的類文件中解壓縮變量和方法的描述符。
非private的變量或方法才會顯示描述符,若為private方法可先改成public/protected然后生成轰传,其描述符是一樣的驴党。
手動書寫
java基本類型和描述符對應(yīng)表:
Java Language Type | Field Desciptor |
---|---|
boolean | Z |
byte | B |
char | C |
short | S |
int | I |
long | J |
float | F |
double | D |
void | V |
對于引用類型,描述符是以"L"開頭获茬,";"結(jié)尾
Java Language Type | Field Desciptor |
---|---|
String | Ljava/lang/String; |
Object[] | [Ljava/lang/Object; |
對于數(shù)組類型港庄,使用"["和對應(yīng)的類型描述符來表述,例
Java Langauage Type | Descriptor |
---|---|
int[][] | [[I |
double[][] | [[[D |
方法描述符一般格式為:(參數(shù)desciptor)返回值desciptor恕曲,示例:
Java Language Method | Method Descriptor |
---|---|
void fun(long v1, String v2, long v3) | (JLjava/lang/String;J)V |
String f(); | ()Ljava/lang/String; |
void fun(byte[] bytes); | ([B)V |
可以使用命令生成來驗證手動寫的是否正確鹏氧。