思考这个问题,在jni中,c语言与c++对方法的调用为啥不一样
1、C语言JNIEnv分析
在C语言中我们对jni是这样处理的
#include <jni.h>
#include <string>
JNIEXPORT jstring
jstring Java_com_hs_androidcmakedemo_MainActivity_GetHell
(JNIEnv *env, jobject job) {
return (*env)->NewStringUTF(env, "string from cplusplus");
}
点开JNIEnv,我们看到jni.h头文件源代码#138行。
typedef const struct JNINativeInterface* JNIEnv;
typedef const struct JNIInvokeInterface* JavaVM;
这里我们看到C语言中的JNIEnv是个指针类型,接着JNIEnv定义了*env,说明env是个二级指针。
那么取值(*env),就是解引用,变成一级指针,如果想访问结构体的方法则需要加个箭头,如下
(*env)->NewStringUTF(env, "string from cplusplus");
又因为C语言中没有this指针,所以这里C语言中所有的函数第一个参数都是JNIEnv,相当于this对象传入调用者
jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);
jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);
jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);
jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);
2、C++语言JNIEnv分析
在C++语言中我们对jni是这样处理的
JNIEXPORT jstring JNICALL
Java_com_hs_androidcmakedemo_MainActivity_GetHell(JNIEnv *env, jobject thiz) {
std::string hello = "Hello from C++";
return env->NewStringUTF(hello.c_str());
}
同样点开JNIEnv,我们看到jni.h头文件源代码#138行。
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
接着打开_JNIEnv,我们发现它是个结构体struct
这里我们看到C++语言中的JNIEnv是个结构体的别名,接着JNIEnv定义了*env,说明env是个一级指针。
一级指针使用箭头函数访问成员,如下
env->NewStringUTF(hello.c_str());
又因为C++中有this指针(当前对象),所以这里不需要额外传env
3、为何设计上C与C++的JNIEnv不同
背景:首先在C语言中没有别名的概念,在C++语言中才开始有别名。而别名用在函数参数接收时特别有用。
分析:在JNIEnv传入到Java_com_hs_androidcmakedemo_MainActivity_GetHell方法中没办法使用别名去接收,这里就必须用指针接收,所以导致了C语言这里出现了二级指针。所以说这里不是不这样做,而是这样做不了。
typedef _JNIEnv JNIEnv;
typedef _JavaVM JavaVM;
jstring Java_com_hs_androidcmakedemo_MainActivity_GetHell
(JNIEnv *env, jobject job) {
return (*env)->NewStringUTF(env, "string from cplusplus");
}
因此开发jni、ndk,使用C++要比C要清爽点