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

2022-01-12  本文已影响0人  MemetGhini

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方法为如下三个步骤:

例如我们为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);
}
上一篇下一篇

猜你喜欢

热点阅读