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

在jni函数中我们不仅要对java对象的数据域进行访问,而且有时也需要调用java中类对象已经实现的方法。接下来我们对对象的方法调用,调用步骤与访问数据域相似。

1.获得实例对应的class2.根据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

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值