目录
以下总结了Android开发中C语言调用java方法的几种情况:
1、非静态native方法调用所在对象中的方法
2、C语言调用java有基础类型返回值的情况
3、C语言调用java有类对象返回值的情况
4、非静态native方法调用本对象中的静态方法
5、非静态native方法调非本对象内的方法 使用NewObject实现
6、非静态native方法调非本对象内的方法 使用AllocObject实现
7、静态\非静态native方法调本对象\非本对象内方法(都需要在底层构造目标java方法相应的类对象)
先总结一下,C语言调用java方法的特点:
1、C语言调用java中方法的语法类似于java中的反射
2、java中的对象映射在C语言中都用jobject表示
以下总结了Android开发中C语言调用java方法的几种情况:
1、非静态native方法调用所在对象中的方法
静态native方法和非静态native方法的区别:
// 非静态java方法映射到C语言中的头文件 JNIEXPORT void JNICALL Java_com_example_jni_CTransferJava_transferJavaFun (JNIEnv *, jobject); // 静态java方法映射到C语言中的头文件 JNIEXPORT void JNICALL Java_com_example_jni_CTransferJava_staticTransferJavaFun (JNIEnv *, jclass);
由于调用非静态native方法需要先创建相应的对象,所以头文件中第二个参数传递的值为所创建的对象,而调用静态native方法无需创建响应的对象,故第二个参数传递的值为响应的类。
C语言部分的代码:
extern "C" JNIEXPORT jint JNICALL
Java_com_example_jni_CTransferJava_transferJavaFun(JNIEnv *jniEnv, jobject object) {
// 找到相应Class
// 注意:方法路径要用 ”/“ 不能使用 ”.“
jclass clazz = jniEnv->FindClass("com/example/jni/CTransferJava");
// 找到相应的方法
//
// 第二个参数:方法名
// 第三个参数:方法签名
jmethodID jmethodId = jniEnv->GetMethodID(clazz, "callFun", "()V");
// 调用java方法
jniEnv->CallVoidMethod(object, jmethodId);
}
如何获得java对应的方法签名?
使用javap命令行获取,例子如下
javap -classpath F:\JNI\app\build\intermediates\javac\debug\compileDebugJavaWithJavac\classes -s com.example.jni.CTransferJava
图中红框均为方法签名。如要获取详细javap的用法,使用javap -help获取
2、C语言调用java有基础类型返回值的情况
extern "C" JNIEXPORT jint JNICALL
Java_com_example_jni_CTransferJava_transferJavaFunReturnInt(JNIEnv *jniEnv, jobject object) {
jclass clazz = jniEnv->FindClass("com/example/jni/CTransferJava");
jmethodID jmethodId = jniEnv->GetMethodID(clazz, "callFunReturnInt", "()I");
// 不同的返回值 调用相应的CallxxMethod方法
return jniEnv->CallIntMethod(object, jmethodId);
}
3、C语言调用java有类对象返回值的情况
extern "C" JNIEXPORT jobject JNICALL
Java_com_example_jni_CTransferJava_transferJavaFunReturnObject(JNIEnv *jniEnv, jobject object) {
jclass clazz = jniEnv->FindClass("com/example/jni/CTransferJava");
jmethodID jmethodId = jniEnv->GetMethodID(clazz, "callFunReturnObject",
"()Lcom/example/jni/CTransferTextClass;");
return jniEnv->CallObjectMethod(object, jmethodId);
}
public native CTransferTextClass transferJavaFunReturnObject();
java中不同的类对象在C语言中统一使用jobject表示,尽管native transferJavaFunReturnObject()方法的返回值是CTransferTextClass,但映射为C方法时,也使用jobject表示。
public CTransferTextClass callFunReturnObject() {
return new CTransferTextClass();
}
C语言调用的java方法的返回值为CTransferTextClass,但是CallObjectMethod返回的也是jobject,而不是具体某个类对象,使用时也无需强转。
注意:当返回值为类时的方法签名,是为()L类名;,不要漏了";"
4、非静态native方法调用本对象中的静态方法
extern "C" JNIEXPORT void JNICALL
Java_com_example_jni_CTransferJava_transferJavaStatic(JNIEnv *jniEnv, jobject) {
jclass clazz = jniEnv->FindClass("com/example/jni/CTransferJava");
// 区别1:获取方法id不同
jmethodID jmethodId = jniEnv->GetStaticMethodID(clazz, "callStaticFun", "()V");
// 区别2:调用java方法不同
jniEnv->CallStaticVoidMethod(clazz, jmethodId);
}
5、非静态native方法调非本对象内的方法 使用NewObject实现
extern "C" JNIEXPORT void JNICALL
Java_com_example_jni_CTransferJava_transferJavaFunOutside(JNIEnv *jniEnv, jobject object) {
jclass clazz = jniEnv->FindClass("com/example/jni/CTransferJavaOutside");
jmethodID jmethodId = jniEnv->GetMethodID(clazz, "callFun", "()V");
// 找出构造方法
jmethodID init = jniEnv->GetMethodID(clazz, "<init>", "(I)V");
// 构造要调用java方法对应的类对象
jobject clazzobj = jniEnv->NewObject(clazz, init, 2);
// 使用目标java方法对应的类对象调用相应的java方法
jniEnv->CallVoidMethod(clazzobj, jmethodId);
}
NewObject和AllocObject的区别
共同点:两个方法都是用于构建一个新的类对象
不同点:AllocObject仅仅构建一个新的类对象(仅仅为类对象分配内存空间而已),不初始成员变量,也不调用构造方法
NewObject需要指明调用的构造方法,构建一个新的类对象,并初始化成员变量,调用指定的构造方法
构造方法的方法名使用<init>代替
6、非静态native方法调非本对象内的方法 使用AllocObject实现
extern "C" JNIEXPORT void JNICALL
Java_com_example_jni_CTransferJava_transferJavaFunOutside_11(JNIEnv *jniEnv, jobject) {
jclass clazz = jniEnv->FindClass("com/example/jni/CTransferJavaOutside");
jmethodID jmethodId = jniEnv->GetMethodID(clazz, "callFun", "()V");
// 区别于NewObject
jobject clazzobj = jniEnv->AllocObject(clazz);
jniEnv->CallVoidMethod(clazzobj, jmethodId);
}
7、静态\非静态native方法调本对象\非本对象内方法(都需要在底层构造目标java方法相应的类对象)
extern "C" JNIEXPORT void JNICALL
Java_com_example_jni_CTransferJava_staticTransferJavaFun(JNIEnv *jniEnv, jclass clazz) {
// 如果非本对象的java方法需要先找出所在类
// 示例为在本对象,故省去找出所在类的步骤
jmethodID jmethodId = jniEnv->GetMethodID(clazz, "callFun", "()V");
// 视情况选择使用NewObject或者AllocObject
jobject clazzobj = jniEnv->AllocObject(clazz);
jniEnv->CallVoidMethod(clazzobj, jmethodId);
}