您的位置:首页 > 编程语言 > Java开发

[JNI]开发之旅(7)JNI函数中调用java对象的方法

2016-12-31 20:51 323 查看
在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对象构造器的访问。

源码下载:https://github.com/honjane/JNIDemo
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: