【Android NDK 开发】JNI 方法解析 ( JNIEnv *env 参数 )
文章目錄
- 一、 JNI 方法解析
- 二、 JNIEnv *env 參數解析
- 三、 C 語言 環境中 JNIEnv *env 參數解析
- 四、 C ++ 環境中 JNIEnv *env 參數解析
總結 : JNI 中定義的函數指針 , 實際都定義在 JNINativeInterface 結構體中 ;
C 語言中的 JNIEnv * env 實際上是 JNINativeInterface ** 類型 , 調用其中的方法指針時 , 先解引用 , 得到其一維指針 , 然后調用對用函數指針 (* env)->函數指針 ;
C++ 中專門定義了 JNIEnv 結構體類型 , 其中的函數直接封裝調用了 JNINativeInterface 結構體中的函數指針 , 只需要調用 JNIEnv 結構體中的方法即可 , C++ 中的 JNIEnv * env , 可以直接調用其中的方法 , 將其當做一個對象使用 , env->方法名稱 , 即可完成調用 ;
一、 JNI 方法解析
1 . JNI 方法定義 :
① 在 Android 的 Java 層定義方法 : 在 MainActivity 類中定義 如下 Native 方法 ;
public native String stringFromJNI();② Native 方法實現 : 下面是一個 Native 方法實現的示例 ;
extern "C" JNIEXPORT jstring JNICALL Java_kim_hsl_jni_MainActivity_stringFromJNI(JNIEnv *env,jobject /* this */) {// 創建 C++ 字符串std::string hello = "Hello from C++";// 返回 jstring 類型的字符串return env->NewStringUTF(hello.c_str()); }2 . 分析上述 JNI 方法 :
① extern “C” : 表示 C 語言 和 C++ 的兼容 ;
② JNIEXPORT jstring JNICALL : 這是兩個宏定義 , 在 Linux 和 Windows 中分別有不同的表示 ; 其中的 jstring 表示返回值類型是 Java 中的 String 類型 ;
關于 JNIEXPORT 與 JNICALL 宏定義 , 參考下面的博客 :
【Android NDK 開發】JNIEXPORT 與 JNICALL 宏定義作用
③ JNIEnv *env : 其中第一個參數 JNIEnv *env 代表了 JNI 環境 ;
④ jobject 參數 : 該 Native 方法定義在 MainActivity 類中 ;
-
1> 非靜態方法 : 如果該方法是非靜態方法 , 那么 jobject 參數表示 MainActivity 類的對象 ;
-
2> 靜態方法 : 如果該方法是靜態方法 , 那么 jobject 參數表示 MainActivity.class ( Class 對象 ) ;
二、 JNIEnv *env 參數解析
在 C 語言 和 C++ 中 , JNIEnv 代表著不同的含義 ;
1 . JNIEnv 類型聲明 :
#if defined(__cplusplus) typedef _JNIEnv JNIEnv; typedef _JavaVM JavaVM; #else typedef const struct JNINativeInterface* JNIEnv; typedef const struct JNIInvokeInterface* JavaVM; #endif由上面的代碼可知 , JNIEnv 是通過 typedef 將其它的類型定義為 JNIEnv 類型的 ;
__cplusplus 是 C++ 編譯器中定義的宏 , C 語言編譯器中沒有定義該宏 , 通過該宏定義 , 可以區分當前是 C++ 環境還是 C語言環境 ;
#if defined(__cplusplus) 分支中聲明的是 C++ 環境下的 JNIEnv 類型 ;
#else 分支中聲明的是 C 語言環境下的 JNIEnv 類型 ;
2 . 兩種 typedef 聲明別名的含義
① C 語言別名 : C 語言中 將 JNINativeInterface 結構體指針 類型 聲明為 JNIEnv 類型 ;
typedef const struct JNINativeInterface* JNIEnv;② C ++ 別名 : C ++ 中 , 將 _JNIEnv 結構體類型聲明為 JNIEnv 類型 ;
typedef _JNIEnv JNIEnv;三、 C 語言 環境中 JNIEnv *env 參數解析
1 . JNIEnv 類型 : C 語言環境中 , 系統將 JNINativeInterface* 類型 聲明為 JNIEnv 別名 ;
2 . JNINativeInterface 結構體 : JNINativeInterface 是結構體類型 , 其中定義了 229 個函數指針 , 用于處理 Java 層 與 Native 層的數據交互信息 ;
3 . C 語言環境中 , 調用 JNINativeInterface 結構體中的函數指針 :
① 類型轉換 : 給定的參數是 JNIEnv *env 類型的 , 即 JNINativeInterface ** env 類型 , 是一個 JNINativeInterface 結構體邊來那個的二級指針 ;
② 通過 JNINativeInterface 指針調用 ( 推薦) : 首先要 解引用 ( *env ) , 該變量就變成了 JNINativeInterface 結構體變量的 一級指針 , 使用 -> 即可調用指定方法 , ( *env ) -> NewStringUTF( “Hello World !” );
③ 通過 JNINativeInterface 結構體調用 ( 不常用 ) : ( **env ).NewStringUTF( “Hello World !” ) , 相當于將上面的 -> 操作符變成 * . 操作符 ;
4 . JNINativeInterface 結構體部分代碼示例 : 該結構體定義在 jni.h 頭文件中 ;
struct JNINativeInterface {void* reserved0;void* reserved1;void* reserved2;void* reserved3;jint (*GetVersion)(JNIEnv *);jclass (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,jsize);jclass (*FindClass)(JNIEnv*, const char*);jmethodID (*FromReflectedMethod)(JNIEnv*, jobject);jfieldID (*FromReflectedField)(JNIEnv*, jobject);/* spec doesn't show jboolean parameter */jobject (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);jclass (*GetSuperclass)(JNIEnv*, jclass);jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass);/* spec doesn't show jboolean parameter */jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);jint (*Throw)(JNIEnv*, jthrowable);jint (*ThrowNew)(JNIEnv *, jclass, const char *);jthrowable (*ExceptionOccurred)(JNIEnv*);void (*ExceptionDescribe)(JNIEnv*);void (*ExceptionClear)(JNIEnv*);void (*FatalError)(JNIEnv*, const char*);...jstring (*NewStringUTF)(JNIEnv*, const char*);... };JNINativeInterface 是結構體類型 , 其中定義了 229 個函數指針 , 用于處理 Java 層 與 Native 層的數據交互信息
四、 C ++ 環境中 JNIEnv *env 參數解析
1 . C++ 環境中 _JNIEnv 類型 : 在 C++ 中 , 將 _JNIEnv 結構體類型 通過 typedef 為其聲明別名 JNIEnv ;
2 . _JNIEnv 結構體 : 該結構體中封裝了一個 JNINativeInterface 結構體類型指針 , _JNIEnv 結構體中也封裝了 229 個 方法 , 每個方法都調用 對應的 JNINativeInterface* functions 中的函數指針 ;
3 . C ++ 語言環境中 , 調用 _JNIEnv 結構體中的函數 :
① 類型轉換 : 給定的參數是 JNIEnv *env 類型的 , 即 _JNIEnv * env 類型 ;
② 通過 _JNIEnv 指針調用 ( 推薦) : 直接使用 -> 符號訪問該方法即可 , env-> NewStringUTF( “Hello World !” );
_JNIEnv 結構體 部分代碼示例 :
struct _JNIEnv {/* do not rename this; it does not seem to be entirely opaque */const struct JNINativeInterface* functions;#if defined(__cplusplus)jint GetVersion(){ return functions->GetVersion(this); }jclass DefineClass(const char *name, jobject loader, const jbyte* buf,jsize bufLen){ return functions->DefineClass(this, name, loader, buf, bufLen); }jclass FindClass(const char* name){ return functions->FindClass(this, name); }jmethodID FromReflectedMethod(jobject method){ return functions->FromReflectedMethod(this, method); }jfieldID FromReflectedField(jobject field){ return functions->FromReflectedField(this, field); }jobject ToReflectedMethod(jclass cls, jmethodID methodID, jboolean isStatic){ return functions->ToReflectedMethod(this, cls, methodID, isStatic); }jclass GetSuperclass(jclass clazz){ return functions->GetSuperclass(this, clazz); }...jstring NewStringUTF(const char* bytes){ return functions->NewStringUTF(this, bytes); }... } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的【Android NDK 开发】JNI 方法解析 ( JNIEnv *env 参数 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Android NDK 开发】JNI
- 下一篇: 【Android NDK 开发】JNI