[JNI]開發之旅(7)JNI函式中呼叫java物件的方法
在jni函式中我們不僅要對java物件的資料域進行訪問,而且有時也需要呼叫java中類物件已經實現的方法。接下來我們對物件的方法呼叫,呼叫步驟與訪問資料域相似。
1.獲得例項對應的class類
2.根據class類獲得方法的method id
3.根據method id和物件例項獲取方法
4.操作方法
例項1:JNI方法java物件public方法
java程式碼
定義一個setSex方法,通過accessPublicMethod在jni實現給java物件的變數sex賦值
private String sex = "female";//需要賦初始值或定義成static,不然在沒有呼叫accessPublicMethod方法前,呼叫getSex方法會拋異常
public void setSex(String sex){
this.sex = sex;
}
public String getSex(){
return sex;
}
public native void accessPublicMethod();
JNI層程式碼
//訪問java中public方法
extern "C"
void Java_com_honjane_ndkdemo_JNIUtils_accessPublicMethod( JNIEnv* env, jobject jobj){
//1.獲得例項對應的class類
jclass jcls = env->GetObjectClass(jobj);
//2.通過class類找到對應的method id
//name 為java類中變數名,Ljava/lang/String; 為變數的型別String
jmethodID jmid = env->GetMethodID(jcls,"setSex","(Ljava/lang/String;)V");
//定義一個性別賦值給java中的方法
char c[10] = "male";
jstring jsex = env->NewStringUTF(c);
//3.通過obj獲得對應的method
env->CallVoidMethod(jobj,jmid,jsex);
}
這裡有幾個地方注意GetMethodID獲取methodID需要傳入jclass,CallVoidMethod需要傳入物件例項jobject,前面文章以及介紹過原因,這裡不在多說;Ljava/lang/String不要寫成Ljava.lang.String否則會找不到方法。
執行結果:
I/main----sex賦值前: female
I/main----sex賦值後: male
呼叫private方法就不用例項實現了,只需要把setSex方法改成private,其他程式碼實現與public沒有區別。在c/c++層,java的訪問域無效。
例項2:JNI方法java物件static方法
java層程式碼:定義一個static的getHeight()方法,通過accessStaticMethod在jni函式中實現呼叫。
private static int height = 160;
public static int getHeight(){
return height;
}
public native int accessStaticMethod();
jni實現:
//訪問java中static方法
extern "C"
jint Java_com_honjane_ndkdemo_JNIUtils_accessStaticMethod( JNIEnv* env, jobject jobj){
//1.獲得例項對應的class類
jclass jcls = env->GetObjectClass(jobj);
//2.通過class類找到對應的method id
jmethodID jmid = env->GetStaticMethodID(jcls,"getHeight","()I");
//3.靜態方法通過class獲得對應的method
return env->CallStaticIntMethod(jcls,jmid);
}
執行結果:
I/main----height呼叫JNI方法: 160
例項3:JNI函式訪問java類的父類方法
java層程式碼:
定義一個SuperUtils讓前面定義的JNIUtils繼承於它,然後在SuperUtils中定義一個hello方法,通過jni實現呼叫java父類方法
public class SuperUtils {
public String hello(String msg){
return "2017 " + msg;
}
}
.....
public class JNIUtils extends SuperUtils{
public native String accessSuperMethod();
......
}
JNI程式碼實現:
//訪問java中父類方法
extern "C"
jstring Java_com_honjane_ndkdemo_JNIUtils_accessSuperMethod( JNIEnv* env, jobject jobj){
//1.通過反射獲得父類的class類
jclass jpcls = env->FindClass("com/honjane/ndkdemo/SuperUtils");
if(jpcls == NULL){
char c[10] = "error";
return env->NewStringUTF(c);
}
//2.通過class類找到對應的method id
jmethodID jmid = env->GetMethodID(jpcls,"hello","(Ljava/lang/String;)Ljava/lang/String;");
char c[20] = "happy new year";
jstring new_str = env->NewStringUTF(c);
//3.靜態方法通過class獲得對應的method
return (jstring)env->CallNonvirtualObjectMethod(jobj,jpcls,jmid,new_str);
}
這裡與前面有幾個不同點:
1.通過反射FindClass獲取到父類的class,而不是JNIUtils的class
2.呼叫CallNonvirtual【Type】Method方法來實現呼叫父類方法
Nonvirtual:繼承而來的非虛擬函
這節簡單的介紹了jni函式怎麼呼叫java物件的方法及父類的方法,要熟悉可以多動手按照上面介紹的步驟,去實現其他型別返回值/引數型別的方法,加深印象。下一節將介紹對java物件構造器的訪問。