<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      C/C++與Java混合的JNI編程

      Java與C++混合編程可以實現兩種語言的優勢結合,C++的程序性能很高且支持強大的系統調用能力,Java則生態豐富且開發效率較高。JNI是Java與C++進行混合編程的關鍵橋梁,本章將基于JNI技術講述Java與C++混合編程的方法和技巧。

      1. Java與JNI

      1.1. 什么是Java?

      Java是一種高級編程語言,也是一個計算平臺(通常指Java虛擬機)。最初由Sun Microsystems公司(后被Oracle收購)的James Gosling和他的團隊在1995年發布。Java語言的設計目標是簡單性、健壯性和跨平臺兼容性。以下是Java的一些關鍵特點:

      • 面向對象: Java是一種面向對象的語言,這意味著它基于對象和類的概念。對象代表現實世界中的實體或概念,而類是創建對象的模板。
      • 平臺無關性: Java的一個核心特性是“一次編寫,到處運行”(Write Once, Run Anywhere,WORA)。Java程序在執行前會被編譯成字節碼,這種中間形式的代碼可以在任何安裝了Java虛擬機(JVM)的設備上運行。
      • 自動內存管理: Java提供了自動垃圾回收機制,這意味著程序員不需要手動管理內存的分配和釋放,從而減少了內存泄漏和其他內存相關錯誤。
      • 豐富的標準庫: Java擁有一個龐大的標準庫(也稱為Java API),提供了大量預先構建的類和接口,用于處理文件輸入/輸出、網絡編程、多線程編程、數據結構等。
      • 跨平臺兼容性: Java不僅可以在不同的操作系統上運行,還可以在嵌入式系統、移動設備和大型服務器上運行。

      Java的應用場景廣泛,是目前最流行的后端系統開發語言,此外Java還是Android系統的主要編程語言,絕大部分的Android應用程序都基于Java語言進行開發。

      1.2. 什么是JVM?

      JVM(Java Virtual Machine)是一個可以執行Java字節碼的虛擬計算機。它是Java平臺的核心組成部分,提供了Java程序運行所需的環境。JVM是Java語言能做到“一次編寫,到處運行”的基礎。以下是JVM的一些關鍵特點和功能:

      • 平臺無關性:JVM的主要目的是實現Java的跨平臺特性。Java源代碼被編譯成平臺無關的字節碼,這些字節碼可以在任何安裝了相應JVM的設備上運行。
      • 字節碼解釋器:JVM包含一個字節碼解釋器,它負責將字節碼轉換為特定平臺的機器碼。這個過程使得Java程序可以在不同的操作系統和硬件上運行。
      • 即時編譯器(JIT):為了提高性能,現代JVM通常包含一個即時編譯器。JIT編譯器會將熱點代碼(頻繁執行的代碼)編譯成優化的機器碼,以提高執行效率。
      • 垃圾回收:JVM負責管理內存分配和回收。它提供了自動垃圾回收機制,幫助程序員管理內存,減少內存泄漏和其他內存相關錯誤。
      • 安全沙箱:JVM提供了一個安全的執行環境,可以限制代碼對系統資源的訪問。這有助于防止惡意代碼對系統造成破壞。
      • 類加載器:JVM包含一個類加載器子系統,負責動態加載、驗證和準備類文件以供執行。類加載器確保類文件的完整性和安全性。
      • 本地接口:JVM提供了與本地庫交互的接口(如JNI,Java Native Interface),允許Java代碼調用本地代碼(C/C++等),以實現特定功能或性能優化。
      • 多線程支持:JVM支持多線程執行,允許程序同時執行多個任務。

      1.3. 什么是JNI?

      JNI(Java Native Interface)是一個允許Java代碼與本地代碼(如:C/C++)進行交互的接口。通過JNI,Java應用程序可以調用本地庫中的函數,也可以被本地代碼調用,它是實現Java與C/C++混合編程的關鍵機制。

      JNI主要包含以下兩部分內容:

      • Java代碼與本地代碼交互的接口。
      • 支持JNI開發的一套開發工具,如: javah、javac等。

      JNI接口的官方文檔:https://docs.oracle.com/en/java/javase/21/docs/specs/jni/index.html

      1.4. 環境說明

      本章所有的示例代碼的開發環境如下:

      • 操作系統: Ubuntu 24.04
      • JDK版本: 21.0.5
      • GCC版本: 13.3.0
      • 開發工具:VSCode

      2. 開發環境搭建

      2.1. Windows

      1. 在官網下載最新版本的安裝包,官網下載地址:https://www.oracle.com/cn/java/technologies/downloads/

      2. 雙擊安裝包,根據提示一步步安裝即可。

      3. 打開命令行輸入一下命令,驗證是否安裝成功,如果有顯示相應的版本號則說明安裝成功。

        java -version
        

      2.2. Linux(Ubuntu)

      安裝JDK:

      # 1. 更新軟件包列表
      sudo apt update
      # 3. 該命令將自動選擇并安裝最新的 LTS 版本,當前是 OpenJDK 21[5]。
      sudo apt install default-jdk
      # 3. 驗證是否安裝成功,如果有顯示相應的版本號則說明安裝成功。
      java --version
      

      設置環境變量:

      # 1. 查找JDK的安裝路徑
      update-alternatives --config java
      There are 2 choices for the alternative java (providing /usr/bin/java).
      
        Selection    Path                                         Priority   Status
      ------------------------------------------------------------
      * 0            /usr/lib/jvm/java-21-openjdk-amd64/bin/java   2111      auto mode
        1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java   1111      manual mode
      
      # 2. vim打開.zshrc(如果你的SHELL用的是.bashrc,替換成相應的.bashrc)
      vim ~/.zshrc
      
      # 3. 在文件末尾添加如下內容
      export JAVA_HOME=/usr/lib/jvm/java-21-openjdk-amd64
      export PATH=${JAVA_HOME}/bin:${PATH}
      
      # 4. 重新加載配置
      source ~/.zshrc
      

      2.3. macOS

      以下是通過Homebrew工具的安裝步驟,確保已經安裝Homebrew。

      # 1. 更新軟件包列表
      brew update
      # 2.1 安裝Oracle JDK的最新版本
      brew install oracle-jdk
      # 2.2 安裝Open JDK的最新版本
      brew install java
      # 3. 驗證是否安裝成功,如果有顯示相應的版本號則說明安裝成功。
      java --version
      

      2.4. Open JDK與Oracle JDK

      Java語言最初由Sun公司研發,并發布了Java SE(Standard Edition)的規范和開源的Open JDK。Sun公司后被Oracle公司收購,Oracle基于Open JDK開發了 Oracle JDK。

      Open JDK是一個完全開源的項目,遵循GPL v2許可。任何人都可以下載、使用、修改和分發它的代碼。主要的Linux發行版(如:Fedora,Ubuntu等)提供OpenJDK作為默認的Java SE實現。

      Oracle JDK則基于Open JDK構建,但包含一些閉源組件,如Java插件、Java WebStart的實現和一些第三方組件。這些組件包括了一些商業功能,未開源。

      Open JDKOracle JDK都遵循Java SE的規范,只是Oracle JDK提供了更多商業版的未開源的功能。

      3. Say Hello程序

      3.1. 新建SayHello.java

      新建一個say_hello的測試目錄,然后在該目錄下新建一個SayHello.java文件,并編寫如下代碼:

      public class SayHello {
      
          // 類方法
          private native void sayHello(String name);
      
          // 靜態方法
          private static native void sayGoodbye(String name);
      
          static {
              // 在程序初始化時加載native動態庫(libhello.so)
              System.loadLibrary("hello");
          }
      
          public static void main(String[] args) {
              new SayHello().sayHello("Spencer");
              SayHello.sayGoodbye("陌塵");
          }
      }
      

      說明:

      • 這里有兩個被聲明為native的方法,表示這兩個方法需要native代碼(C/C++)實現。這里一個是普通的類成員方法,一個是靜態的類方法。

        private native void sayHello(String name);
        private static native void sayGoodbye(String name);
        
      • static包含的代碼塊,表示在程序初始化時加載native動態庫(libhello.so)

        static {
            System.loadLibrary("hello");
        }
        

      3.2. 編譯SayHello.java

      javac ./SayHello.java
      

      執行完成后,會生成一個SayHello.class的字節碼文件。

      3.3. 生成SayHello.h

      執行以下命令生成native代碼的頭文件

      # JDK 9.0 之前
      javah -cp ./ -d ./ SayHello
      # `-cp ./`表示設置classpath為當前目錄,在當前目錄下查找.class文件
      # `-d ./`表示設置頭文件的輸出目錄為當前目錄
      
      # JDK 9.0 及之后
      javac -h ./ ./SayHello.java
      # 第一個`./` 表示設置頭文件的輸出目錄為當前目錄
      

      執行成功后會在當前目錄下生成SayHello.h頭文件,內容如下:

      /* DO NOT EDIT THIS FILE - it is machine generated */
      #include <jni.h>
      /* Header for class SayHello */
      
      #ifndef _Included_SayHello
      #define _Included_SayHello
      #ifdef __cplusplus
      extern "C" {
      #endif
      /*
       * Class:     SayHello
       * Method:    sayHello
       * Signature: (Ljava/lang/String;)V
       */
      JNIEXPORT void JNICALL Java_SayHello_sayHello
        (JNIEnv *, jobject, jstring);
      
      /*
       * Class:     SayHello
       * Method:    sayGoodbye
       * Signature: (Ljava/lang/String;)V
       */
      JNIEXPORT void JNICALL Java_SayHello_sayGoodbye
        (JNIEnv *, jclass, jstring);
      
      #ifdef __cplusplus
      }
      #endif
      #endif
      

      代碼說明:

      • 頭文件中包含兩個函數分別和.java中的兩個方法一一對應。

      • 函數聲明中開通的部分JNIEXPORT void JNICALL,這個與《導出接口的定義》一文中的EAPI int CALLType是不是非常類似?是的,它就是JNI提供的動態庫導出接口聲明和調用約定聲明。

      • 函數的命名非常有規律,其實它是遵循了JNI的函數命名規范:

        Java_{package_name}_{class_name}_{function_name}(JNI arguments)。
        
      • 函數的參數

        • 第一個參數:JNIEnv *env是一個指向JNI運行環境的指針,提供了JNI接口的各種功能函數。
        • 第二個參數:
          • 如果是一個普通的成員方法則參數為jobject obj,指代java中的this對象,可以通過該參數來獲取Java對象的方法和屬性。
          • 如果是一個靜態的類方法則參數為jclass cls,指代java中的類,可以通過該參數來獲取Java類的靜態方法和靜態屬性。
        • 其他參數: 按從左到右的順序與.java中聲明的方法的參數一一對應。

      3.4. 實現SayHello.cp

      新建SayHello.cpp文件,并實現頭文件聲明的兩個函數,內容如下:

      #include "SayHello.h"
      #include <iostream>
      
      JNIEXPORT void JNICALL Java_SayHello_sayHello(JNIEnv* env, jobject obj, jstring name)
      {
          // 將jstring轉化成C風格的UTF-9字符串
          const char* cName = env->GetStringUTFChars(name, nullptr);
          if (cName == nullptr)
          {
              return;
          }
          std::cout << "Hello, " << cName << "!" << std::endl;
      }
      
      JNIEXPORT void JNICALL Java_SayHello_sayGoodbye(JNIEnv* env, jclass cls, jstring name)
      {
          // 將jstring轉化成C風格的UTF-9字符串
          const char* cName = env->GetStringUTFChars(name, nullptr);
          if (cName == nullptr)
          {
              return;
          }
          std::cout << "Goodbye, " << cName << "!" << std::endl;
      }
      

      3.5. 編譯SayHello.cpp

      g++ -shared -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux SayHello.cpp -o libhello.so
      

      執行成功后會生成libhello.so文件。

      3.6. 運行SayHello程序

      java -Djava.library.path=./ SayHello
      Hello, Spencer!
      Goodbye, 陌塵!
      

      -Djava.library.path=./表示在當前目錄下查找libhello.so。

      4. JNI開發的關鍵步驟

      根據前面“Say Hello程序”的示例,可以總結出JNI開發的關鍵步驟和原理如下:

      1. 本地方法聲明:在Java中,你可以聲明一個或多個本地方法,這些方法沒有Java實現,而是通過JNI與本地代碼關聯。
      2. 生成頭文件:使用javah(或javac -h)工具從Java類生成C/C++頭文件,該頭文件包含JNI函數的原型。
      3. 實現本地方法:在C或C++代碼中實現這些本地方法。這些方法必須遵循JNI的調用約定和數據類型規范。
      4. 編譯和加載:編譯本地代碼并生成動態鏈接庫(如.so.dll.dylib文件),然后在Java程序中加載這些庫。
      5. 調用本地方法:Java程序可以通過JNI調用這些本地方法,就像調用普通Java方法一樣。

      5. 數據類型的對應關系

      5.1. 對應關系

      JNI定義了一套以j開頭的C/C++的數據類型,與Java進行一一對應,他們之間的對應關系如下:

      分類 Java數據類型 JNI數據類型 C/C++數據類型
      基礎類型 boolean jboolean unsigned char,相當于uint8_t
      基礎類型 byte jbyte signed char,相當于int8_t。
      基礎類型 char jchar unsigned short,相當于uint16_t。
      基礎類型 short jshort short,相當于int16_t。
      基礎類型 int jint int,相當于int32_t。
      基礎類型 long jlong long,相當于int64_t
      基礎類型 float jfloat float,4字節
      基礎類型 double jdouble double,8字節
      引用類型 Object jobject jobject的定義:
      class _jobject {};
      typedef _jobject *jobject;
      所以jobject的作用類似于void*,表示通用對象指針。
      引用類型 Class jclass class _jclass : public _jobject {};
      typedef _jclass *jclass;
      引用類型 String jstring class _jstring : public _jobject {};
      typedef _jstring *jstring;
      引用類型 數組 jarray class _jarray : public _jobject {};
      typedef _jarray *jarray;
      引用類型 Throwable jthrowable class _jthrowable : public _jobject {};
      typedef _jthrowable *jthrowable;

      5.2. 類型說明

      Java的數據類型分基礎數據類型(如int)和引用數據類型(如:ObjectClass)。

      基礎數據類型: 會直接轉換為C/C++的基礎數據類型,例如int類型映射為jint類型。由于 jint是C/C++類型,所以可以直接當作普通C/C++變量使用,而不用做任何轉換。
      引用數據類型: 對象只會轉換為一個C/C++指針,例如Object類型映射為jobject類型。由于指針指向Java虛擬機內部的數據結構,所以不可能直接在C/C++代碼中操作對象,而是需要依賴JNIEnv環境對象。另外,為了避免對象在使用時突然被回收,在本地方法返回前,虛擬機會固定(pin)對象,阻止其 GC。

      Java中的數組對應于C/C++中的jarray,它是一個通用的數組類型。而具體數據類型的數組,對應于Java數組的特定類型,對應關系如下。

      Java數據類型 JNI數據類型
      boolean[] jbooleanArray
      byte[] jbyteArray
      char[] jcharArray
      short[] jshortArray
      int[] jintArray
      long[] jlongArray
      float[] jfloatArray
      double[] jdoubleArray
      Object[] jobjectArray

      歷史文章推薦:

      01. 概念篇:什么是SDK

      02. 概念篇:SDK的設計目標

      03. 概念篇:接口設計與規范

      04. 概念篇:接口注釋與接口文檔

      05. 原理篇:字符集與字符編碼(一)

      06. 原理篇:字符集與字符編碼(二)

      07. 原理篇:多字節字符與寬字節字符

      08. 原理篇:靜態庫、動態庫與運行庫

      09. 跨平臺:C++標準的版本

      10. 跨平臺:源碼的保存格式與中文亂碼問題

      11. 跨平臺:宏定義隔離平臺差異

      12. 跨平臺:基礎數據類型的定義

      13. 跨平臺:文件系統的操作

      14. 跨平臺:頭文件包含的差異

      15. 跨平臺:導出接口的定義

      16. 跨平臺:字節序大端與小端

      17. 跨平臺:內存和資源管理

      18. 工程篇:C/C++常用編譯器

      19. 工程篇:用VSCode搭建C++開發環境

      20. 工程篇:CMake實現跨平臺構建

      21. 工程篇:VSCode中使用CMake插件運行和調試程序

      22. 跨語言:跨語言的混合編程

      23. 跨語言:C++接口設計和代碼實現

      24. 跨語言:C語言接口設計和代碼實現

      25. 跨語言:C/C++與Python混合編程(一)

      26. 跨語言:C/C++與Python混合編程(二)

      27. 跨語言:C/C++與Python混合編程(三)

      28. 跨語言:C/C++與JavaScript的WebAssembly編程(一)

      29. 跨語言:C/C++與JavaScript的WebAssembly編程(二)

      30. 跨語言:C/C++與JavaScript的WebAssembly編程(三)

      31. 跨語言:C/C++與Java混合的JNI編程(一)

      32. 跨語言:C/C++與Java混合的JNI編程(二)

      33. 跨語言:C/C++與Java混合的JNI編程(三)

      34. 跨語言:Android NDK編程(一)

      35. 跨語言:Android NDK編程(二)

      36. 跨語言:C/C++與Swift&Objective-C混合編程(一)

      37. 跨語言:C/C++與Swift&Objective-C混合編程(二)

      附錄A:計算機術語中成對出現的單詞

      附錄B:計算機術語中常見的單詞縮寫

      附錄C:本專欄源碼倉庫及說明


      大家好,我是陌塵。

      IT從業10年+, 北漂過也深漂過,目前暫定居于杭州,未來不知還會飄向何方。

      搞了8年C++,也干過2年前端;用Python寫過書,也玩過一點PHP,未來還會折騰更多東西,不死不休。

      感謝大家的關注,期待與你一起成長。



      【SunLogging】
      掃碼二維碼,關注微信公眾號,閱讀更多精彩內容
      posted @ 2025-08-08 07:41  陌塵(MoChen)  閱讀(307)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 一道本AV免费不卡播放| 亚洲综合久久一区二区三区| 最新中文字幕国产精品| 国内久久人妻风流av免费| 午夜福利片1000无码免费| 久久精品国产99国产精品严洲| 最新中文字幕国产精品| 日本高清中文字幕免费一区二区| 欧美黑人巨大xxxxx| P尤物久久99国产综合精品| 亚洲性日韩一区二区三区| 亚洲码国产精品高潮在线| 久久亚洲国产品一区二区| 欧美牲交a欧美牲交aⅴ图片| 永久免费av网站可以直接看的| 亚洲人成人伊人成综合网无码| 色狠狠色婷婷丁香五月| 成人午夜在线观看刺激| 久久发布国产伦子伦精品| 亚洲国产成人不卡高清麻豆| 中文字幕无码av不卡一区| 四虎国产精品永久入口| 国产中文三级全黄| 狠狠综合久久久久综| 老司机性色福利精品视频| 国内精品卡一卡二卡三| 亚洲综合成人一区二区三区| 噜噜噜噜私人影院| 乱码精品一区二区三区| 国产成人精品视频国产| 国产美女裸身网站免费观看视频| 大又大又粗又硬又爽少妇毛片| 澄迈县| 黄又色又污又爽又高潮| 97精品国产91久久久久久久| 久久久一本精品99久久精品36| 四虎国产成人永久精品免费| 亚洲日韩av无码中文字幕美国| 国产精品一区二区三区性色| 国产av中文字幕精品| 久久亚洲AV成人网站玖玖|