★02.入門

簡介

  • 本節示例怎么使 Java應用程序 通過 JNI 調用 C語言 輸出Hello World!

流程

  1. 創建一個HelloWorld.java文件并聲明原生方法。
  2. 使用 javac 編譯HelloWorld.java,生成HelloWorld.class文件。
  3. 使用 javah 生成C頭文件HelloWorld.h,該頭文件包含了原生函數實現的原型。
  4. 新建文件HelloWorld.c并按照HelloWorld.h中聲明的原生函數原型實現原生代碼。
  5. HelloWorld.c構建成為一個原生庫,生成HelloWorld.dll或者HelloWorld.so
  6. 使用 Java 運行HelloWorld程序,HelloWorld.classHelloWorld.dll/so會在運行時被加載。
JNI Hello World 示意圖

HelloWorld示例

1. 創建HelloWorld.java

代碼

public class HelloWorld {
    static {
        // "HelloWorld" 表明載入HelloWorld.dll
        System.loadLibrary("HelloWorld");
    }

    public static void main(String[] args) {
        new HelloWorld().print();
    }

    private native void print();
}

解說

  • 上述代碼主要包含三個部分:
    1. 一個靜態代碼塊,用來加載 動態鏈接庫
    2. 一個主函數作為 Java應用程序 入口,并在主函數中調用print
    3. 一個原生函數print的聲明,由原生代碼實現。
  • 包含原生代碼的 動態鏈接庫 一定要提前加載。
  • print函數聲明中的native修飾符表示該函數是使用其他語言實現的。

2. 生成HelloWorld.class

  • 編譯產生HelloWorld.class

3. 使用CLion創建C/C++項目

  • 保證 CLion 使用的是 MinGW-w64 而不是 MinGW-32
  • 設置JAVAHOME環境變量,指向 jdk 目錄。
  • 通過CMakeList.txt設置 JNI 包含目錄。
  • 通過CMakeList.txt設置構建完畢后自動復制 DLLJava 項目目錄下。
  • CMakeList.txt文件參考,
cmake_minimum_required(VERSION 3.7)
project(JNI_c)

set(CMAKE_C_STANDARD 11)

# 相當于 SOURCE_FILES = "HelloWorld.h HelloWorld.c"
set(SOURCE_FILES HelloWorld.h HelloWorld.c)
add_library(JNI_c SHARED ${SOURCE_FILES})

include_directories($ENV{JAVAHOME}/include)
include_directories($ENV{JAVAHOME}/include/win32)

# 設置輸出DLL的名字前綴
set_target_properties(JNI_c PROPERTIES PREFIX "")
# 設置輸出DLL的名字,此處輸出HelloWorld.dll
set_target_properties(JNI_c PROPERTIES OUTPUT_NAME "HelloWorld")

# 構建完后復制DLL到指定目錄
add_custom_command(TARGET JNI_c POST_BUILD                     # JNI_c是項目名稱
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        "$<TARGET_FILE_DIR:JNI_c>/HelloWorld.dll"           # input dir
        "C:/ProgramProjects/Java/JNI")                         # output dir

4. 生成HelloWorld.h

1. 配置 IDEA 中生成頭文件規則(已配置則跳過)

  1. File -> Settings -> External Tools。
  2. 點擊 “+” 按鈕。
    1. Name : 生成頭文件
    2. Group : JNI
    3. Options : 全部勾選。
    4. Show in : 全部勾選。
    5. Program : $JDKPath$\bin\javah.exe
    6. Parameters : -jni -v -d $FileDir$ $FileClass$$FileDir$表示輸出目錄,將$FileDir$設置為 CLion 項目目錄。
    7. Working directory : $SourcepathEntry$
  3. 點擊確定。

2. 生成

  1. 選擇對應的java文件。
  2. 右鍵 -> JNI -> Generate Header File。
  3. $FileDir$對應的目錄里生成了HelloWorld.h

3. 解說HelloWorld.h文件

代碼

/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv * , jobject);

解說

  • 注釋部分:
    • Class :函數來自的那一個類的名字。
    • Method :這個函數的名字。
    • Signature :這個函數的簽名。
      • ()V:函數的簽名為void ()
      • (IFC)D:這個函數的double (int, float, char)
  • 代碼部分:
    • void:原方法的返回值。
    • JNIEnv *:一個JNIEnv接口指針。
    • jobjectHelloWorld對象本身,有點像 C++ 中的this指針。

5. 實現HelloWorld.c

#include <jni.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print(JNIEnv * env, jobject obj) {
    printf("Hello World!\n");
}

#ifdef __cplusplus
}
#endif

5. 生成動態鏈接庫并運行

  • Clion 中構建項目,生成 DLL 到對應目錄。
  • 設置 IDEA 中的 Run/Debug Configurations
    • VM Options 設置為-Djava.library.path=C:\ProgramProjects\Java\JNI\
  • 運行程序。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前文件,而是在用其他語言(如C和C++)...
    時待吾閱讀 586評論 0 2
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,466評論 25 708
  • 你有沒有想過從來沒愛過什么人會是什么樣的感覺,會過怎么樣的人生,會變成一個怎樣的人。吶,我就是那個長了二十年沒...
    胖胖的張二十閱讀 446評論 0 2
  • 集。人多,卻不忙。 臨門而立,看熙熙攘攘人來人往,人間百態,世俗民情,盡在眼底。大俗,卻不失熱鬧。 對...
    雪下冰閱讀 417評論 0 2