簡介
- 本節示例怎么使 Java應用程序 通過 JNI 調用 C語言 輸出
Hello World!
。
流程
- 創建一個
HelloWorld.java
文件并聲明原生方法。 - 使用 javac 編譯
HelloWorld.java
,生成HelloWorld.class
文件。 - 使用 javah 生成C頭文件
HelloWorld.h
,該頭文件包含了原生函數實現的原型。 - 新建文件
HelloWorld.c
并按照HelloWorld.h
中聲明的原生函數原型實現原生代碼。 - 將
HelloWorld.c
構建成為一個原生庫,生成HelloWorld.dll
或者HelloWorld.so
。 - 使用 Java 運行HelloWorld程序,
HelloWorld.class
和HelloWorld.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();
}
解說
- 上述代碼主要包含三個部分:
- 一個靜態代碼塊,用來加載 動態鏈接庫 。
- 一個主函數作為 Java應用程序 入口,并在主函數中調用
print
。 - 一個原生函數
print
的聲明,由原生代碼實現。
- 包含原生代碼的 動態鏈接庫 一定要提前加載。
-
print
函數聲明中的native
修飾符表示該函數是使用其他語言實現的。
2. 生成HelloWorld.class
- 編譯產生
HelloWorld.class
。
3. 使用CLion創建C/C++項目
- 保證 CLion 使用的是 MinGW-w64 而不是 MinGW-32 。
- 設置
JAVAHOME
環境變量,指向 jdk 目錄。 - 通過
CMakeList.txt
設置 JNI 包含目錄。 - 通過
CMakeList.txt
設置構建完畢后自動復制 DLL 到 Java 項目目錄下。 -
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 中生成頭文件規則(已配置則跳過)
- File -> Settings -> External Tools。
- 點擊 “+” 按鈕。
-
Name :
生成頭文件
。 -
Group :
JNI
。 - Options : 全部勾選。
- Show in : 全部勾選。
-
Program :
$JDKPath$\bin\javah.exe
。 -
Parameters :
-jni -v -d $FileDir$ $FileClass$
。$FileDir$
表示輸出目錄,將$FileDir$
設置為 CLion 項目目錄。 -
Working directory :
$SourcepathEntry$
。
-
Name :
- 點擊確定。
2. 生成
- 選擇對應的java文件。
- 右鍵 -> JNI -> Generate Header File。
- 在
$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
接口指針。 -
jobject
:HelloWorld
對象本身,有點像 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\
- 將 VM Options 設置為
- 運行程序。