在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对象构造器的访问。