美文网首页
JNI基础(8): JNI调用Java方法

JNI基础(8): JNI调用Java方法

作者: MemetGhini | 来源:发表于2022-01-12 23:29 被阅读0次

    8.1 JNI调用Java类的成员方法和静态方法

    首先需要了解一下java方法在jni中签名格式。简单来说: (参数签名直接拼接)返回值类型的签名。例如:

    Point test(int x,float y)       --> (IF)Ljava/awt/Point;
    Object[] test(byte x,char y)    --> (BC)[Ljava/lang/Object;
    String fun();                   --> ()Ljava/lang/String;
    long f(int I, Class c);         --> (ILjava/lang/Class;)J
    void f(byte[] bytes);           --> ([B)V
    

    JNI中调用java方法为如下三个步骤:

    • env->GetObjectClass(xxx) 找到类jclass
    • env->Get[Static(静态或者非静态)]MethodID(...) 找到方法id
    • env->Call[Void/Object/Boolen(返回值类型)]Method(obj, jmid, ...); 来调用方法

    例如我们为Person添加如下方法:

    public void callInstanceMethod(int num)
    {
        Log.i("JNI-MG", "instance method called with : num = " + num);
    }
    public static String callStaticMethod(String str)
    {
        Log.i("JNI-MG", "static called with : " + str);
        return "static return" + str;
    }
    public static String callStaticMethod(String[] strs, int num)
    {
        if (strs != null)
        {
            for (String str : strs)
            {
                Log.i("JNI-MG", "static called with : " + str);
            }
        }
        Log.i("JNI-MG", "static called with num : " + num);
        return "static return with num = " + num;
    }
    

    在默认工程MainActivity中添加public static native void callFromNative(Person person);并在JNI中进行调用验证:

    extern "C"
    JNIEXPORT void JNICALL
    Java_com_memetghini_javaobject_MainActivity_callFromNative(JNIEnv *env, jclass clazz, jobject person) {
        //调用非静态方法
        //首先找到类
        jclass cls = env->GetObjectClass(person);
        //再找到该类的方法id
        jmethodID jmid = env->GetMethodID(cls, "callInstanceMethod", "(I)V");
        //然后调用
        env->CallVoidMethod(person, jmid, 99);
    
        //调用静态方法
        //上面已经找打类,接下来直接找到方法id
        jmethodID  jmid2 = env->GetStaticMethodID(cls, "callStaticMethod", "(Ljava/lang/String;)Ljava/lang/String;");
        jstring s = (jstring)env->CallStaticObjectMethod(cls, jmid2, env->NewStringUTF("Kadi"));
        const char* cc = env->GetStringUTFChars(s, 0);
        LOGI("java 返回的 : %s", cc);
        env->ReleaseStringUTFChars(s, cc);
    
        //调用静态方法with数组
        jmethodID  jmid3 = env->GetStaticMethodID(cls, "callStaticMethod", "([Ljava/lang/String;I)Ljava/lang/String;");
        //构造参数
        jclass strClass = env->FindClass("java/lang/String");
        int size = 3;
        jobjectArray obj_array = env->NewObjectArray(size, strClass, nullptr);
        jstring strItem;
        for (int i = 0; i < size; ++i)
        {
            strItem = env->NewStringUTF("Test String");
            env->SetObjectArrayElement(obj_array, i, strItem);
        }
        env->CallStaticObjectMethod(cls, jmid3, obj_array, 1);
    }
    

    8.2 JNI 访问Java类的构造方法

    在JNI中创建java类的流程跟调用普通方法是一样的,比较特殊的地方是构造方法名为<init>,没有返回值。

    例如构造Person类并返回:

    //方式1
    jclass cls = env->FindClass("com/memetghini/javaobject/Person");
    jmethodID mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
    jstring js = env->NewStringUTF("MemetGhini");
    jobject obj = env->NewObject(cls, mid, js); //直接new一个对象
    return obj;
    
    //方式二
    jclass cls = env->FindClass("com/memetghini/javaobject/Person");
    jmethodID mid = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;)V");
    jstring js = env->NewStringUTF("MemetGhini 2222");
    jobject obj = env->AllocObject(cls);//先开辟内存 在调用构造方法
    env->CallVoidMethod(obj, mid, js);
    

    8.3 JNI中访问父类的方法

    调用被子类覆盖的父类方法需要用env->CallNonvirtualVoidMethod(obj, cls, mid);方法。cls需要传父类的class即可。相当于java中的super.func()调用。

    例如:创建一个class叫Son 继承自 Person

    public class Son extends Person {
        public Son(String name) {
            super(name);
        }
        public void run() {
            Log.i("JNI-MG", "Son run。");
        }
    }
    

    并在父类Person中也实现run() 方法:

    public void run() {
        Log.i("JNI-MG", "Person run。");
    }
    

    在默认工程MainActivity中添加JNI方法声明public static native void callFatherFun(Son son); 参数为son,我们在jni中实现调用父类的run方法。

    extern "C"
    JNIEXPORT void JNICALL
    Java_com_memetghini_javaobject_MainActivity_callFatherFun(JNIEnv *env, jclass clazz, jobject son) {
        //查找父类的类jclass
        jclass cls = env->FindClass("com/memetghini/javaobject/Person"); //父类的class
        //如果调用son的run方法需要查找son的类
        //jclass cls = env->GetObjectClass(son);
        //查找方法id
        jmethodID  mid = env->GetMethodID(cls, "run", "()V");
        //通过CallNonvirtualVoidMethod调用
        env->CallNonvirtualVoidMethod(son, cls, mid);
    }
    

    相关文章

      网友评论

          本文标题:JNI基础(8): JNI调用Java方法

          本文链接:https://www.haomeiwen.com/subject/zxlpcrtx.html