<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                接續上篇[JNI開發系列①JNI概念及開發流程](http://www.jianshu.com/p/68bca86a84ce) ### 前情提要 JNI技術 , 是java世界與C/C++世界的通信基礎 , java語言可以通過native方法去調用C/C++的函數 , 也可以通過C/C++來調用java的字段與方法 。 在上篇中 , 我們了解了JNI開發的基本流程 , 接下來我們來分析分析C語言代碼以及頭文件 。 ### .h頭文件分析 > 頭文件生成命令 : javah com.zeno.jni.HelloJni ```java public static native String getStringFromC() ; ``` 上述代碼 通過`javah`命令 , 則會生成如下頭文件中的函數: ```c /* DO NOT EDIT THIS FILE - it is machine generated */ #include "jni.h" /* Header for class com_zeno_jni_HelloJni */ #ifndef _Included_com_zeno_jni_HelloJni #define _Included_com_zeno_jni_HelloJni #ifdef __cplusplus extern "C" { #endif /* * Class: com_zeno_jni_HelloJni * Method: getStringFormC * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJni_getStringFromC (JNIEnv *, jclass); #ifdef __cplusplus } #endif #endif ``` 通過上述代碼, 我們可以看出`getStringFromC()`方法 , 生成的函數是`Java_com_zeno_jni_HelloJni_getStringFromC (JNIEnv *, jclass)`函數 。其實 ,我們不用`javah`命令 , 也能寫出頭文件 , 除了`#endif,#ifdef __cplusplus`中間是變化的 , 其他的都不變 , `javah`通過`native`方法生成的函數 , 命名都是有規律 。 ``` 函數名稱規則:Java_完整類名_方法名 , 包名的.號 , 以`_`表示 ``` > 其中jstring是返回的java的String類型 , jstring類型是jni里面定義的類型 , 標準C里面是沒有的 。那么 , jstring是什么類型呢 ? 使用VS的轉到定義功能 , 我們可以看到 , jstring在jni.h的定義 , jstring是jobject的別名 , jobject是一個_jobject結構體的指針 。 ```c typedef jobject jstring; typedef struct _jobject *jobject; ``` 因為我們`getStringFromC()`方法返回的是一個String類型 , 所以C函數的返回值是`jstring`類型 。 ```c /* * Class: com_zeno_jni_HelloJni * Method: getStringFormC * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJni_getStringFromC (JNIEnv *Env, jclass jclazz) { return (*Env)->NewStringUTF(Env, "Jni C String"); } ``` 在C語言系列的最后一篇 , 我們分析了jni.h的頭文件 , 了解了JNIEnv結構體指針 , 大致知道里面都有些什么函數 , `NewStringUTF(Env, "Jni C String")`這個函數 , 就是將C語言中的字符指針轉換成java的`String`類型的字符串。 ### JNI數據類型對應java的標準數據類型 |Java Type|Native Type|Description| |:----:|:----:|:----:| |boolean|jboolean|unsigned 8 bits| |byte|jbyte|signed 8 bits| |char|jchar|unsigned 16 bits| |short|jshort|signed 16 bits| |int|jint|signed 32 bits| |long|jlong|signed 64 bits| |float|jfloat|32 bits| |double|jdouble|64 bits| |void|void|not applicable| ### JNI數據類型對應java的引用數據類型 ```c struct _jobject; typedef struct _jobject *jobject; typedef jobject jclass; typedef jobject jthrowable; typedef jobject jstring; typedef jobject jarray; typedef jarray jbooleanArray; typedef jarray jbyteArray; typedef jarray jcharArray; typedef jarray jshortArray; typedef jarray jintArray; typedef jarray jlongArray; typedef jarray jfloatArray; typedef jarray jdoubleArray; typedef jarray jobjectArray; ``` 在jni源碼中 , 我們可以看到如上定義 , 可以發現 , 所有的引用類型都是`_jobject `結構體指針類型。 ### JNIEnv分析 我們知道 ,JNIEnv是`JNINativeInterface_`結構體的指針別名 , 在`JNINativeInterface_`結構體中 , 定義很多操作函數 。例如: ```c jstring (JNICALL *NewStringUTF) (JNIEnv *env, const char *utf); jsize (JNICALL *GetStringUTFLength) (JNIEnv *env, jstring str); const char* (JNICALL *GetStringUTFChars)(JNIEnv *env, jstring str, jboolean *isCopy); void (JNICALL *ReleaseStringUTFChars)(JNIEnv *env, jstring str, const char* chars); ``` 由上述函數可以看出,每個函數都需要一個JNIEnv指針,但是為什么需要呢 ? > 有兩點: 第一:函數需要 , 在函數中仍然需要JNINativeInterface_結構體中的函數做處理 第二:區別對待C和C++ 我們知道 , jni是支持C/C++的,在jni.h頭文件中 , 那么C++是怎么表示JNIEnv的呢 ?源碼如下: ```c++ struct JNIEnv_ { const struct JNINativeInterface_ *functions; #ifdef __cplusplus jint GetVersion() { return functions->GetVersion(this); } jclass DefineClass(const char *name, jobject loader, const jbyte *buf, jsize len) { return functions->DefineClass(this, name, loader, buf, len); } jclass FindClass(const char *name) { return functions->FindClass(this, name); } jmethodID FromReflectedMethod(jobject method) { return functions->FromReflectedMethod(this,method); } ``` 在C++環境下 ,還是使用的`NINativeInterface_`結構體指針調用函數, 使用`NewStringUTF`函數時, 則不需要傳入`Env`這個二級指針 ,因為C++是面向對象的語言 , 傳入了this , 當前環境的指針 ```c++ jstring NewStringUTF(const char *utf) { return functions->NewStringUTF(this,utf); } ``` 示例: ```c++ /* * Class: com_zeno_jni_HelloJni * Method: getStringFormC * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_zeno_jni_HelloJni_getStringFromCPP (JNIEnv * env, jclass jclazz) { return env->NewStringUTF("From C++ String"); } ``` 在C++環境中 , JNIEnv就成了一級指針了 , 為什么會是這樣呢 ?我們在源碼中找到這樣一段代碼: ```c /* * JNI Native Method Interface. */ struct JNINativeInterface_; struct JNIEnv_; #ifdef __cplusplus typedef JNIEnv_ JNIEnv; #else typedef const struct JNINativeInterface_ *JNIEnv; #endif ``` 由上可知 , 在C和C++兩個環境中 , 使用了兩個不同的JNIEnv , 一個是JNIEnv二級指針 , 一個是JNIEnv一級指針 。 ### 模擬C語言中的JNIEnv寫法 ```c #include <stdio.h> #include <stdlib.h> // 定義一個JNIEnv , 是JavaNativeInterface結構體指針的別名 typedef struct JavaNativeInterface* JNIEnv; // 模擬java本地化接口結構體 struct JavaNativeInterface { void(*hadlefunc)(JNIEnv*); char*(*NewStringUTF)(JNIEnv*, char*); }; // 模擬 , 在調用NewStringUTF函數的時候 , 需要處理一些事情 void handleFunction(JNIEnv* env) { printf("正在處理...\n"); } // 最終調用的函數實現 char* NewStringUTF(JNIEnv* env,char* utf) { (*env)->hadlefunc(env); return utf; } void main() { //實例化結構體 struct JavaNativeInterface jnf; jnf.hadlefunc = handleFunction; jnf.NewStringUTF = NewStringUTF; // 結構體指針 JNIEnv e = &jnf; // 二級指針 JNIEnv* env = &e; // 通過二級指針掉用函數 char* res = (*env)->NewStringUTF(env, "模擬JNIEnv實現方式\n"); // 打印 printf("調用結果:%s", res); system("pause"); } ``` 輸出: ```c 正在處理... 調用結果:模擬JNIEnv實現方式 ``` ###結語 .h頭文件的分析就到這里 ,關鍵是了解清楚 , `native`方法在C中生成函數名稱的規則 , 以及對JNIEnv有個良好的認識 。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看