Java 原生介面 (JNI) 讓 Java 程式能夠呼叫 C/C++ 編寫的本地程式碼,這對於效能敏感模組、硬體驅動或既有程式庫整合至關重要。本文將詳細示範從建立 Java 類別、產生 C++ 標頭檔、在 Visual Studio 建立 DLL 專案,到最終在 Java 中載入並呼叫的完整流程。
首先建立一個包含 native 方法的 Java 類別:
public class Main {
public native static int getStrNum(byte[] str, int strLen);
}
開啟命令提示字元,切換至 Main.java 所在目錄,依序執行:
javac Main.java
javah Main
執行完成後會在目錄下產生 Main.h,其中包含 JNI 所需的函式原型宣告。
MakeDLL,勾選 Empty project。C:\Program Files\Java\jdk1.8.0_XXX\includeC:\Program Files\Java\jdk1.8.0_XXX\include\win32(請依實際 JDK 安裝路徑調整)
將產生的 Main.h 加入專案。新增 main.cpp 並實作 JNI 函式:
#include "Main.h"
#include <string.h>
JNIEXPORT jint JNICALL Java_Main_getStrNum(JNIEnv *env, jclass cls, jbyteArray str, jint strLen) {
jbyte *buffer = (*env)->GetByteArrayElements(env, str, 0);
buffer[strLen] = '\0'; // 確保字串結尾
jint len = strlen((char*)buffer);
(*env)->ReleaseByteArrayElements(env, str, buffer, 0); // 釋放資源
return len;
}
注意:實際專案中務必呼叫 ReleaseByteArrayElements 避免記憶體洩漏。
按 F7 建置方案,輸出目錄下將產生 MakeDLL.dll。
將 MakeDLL.dll 複製到 Java 類別檔相同目錄,或設定 java.library.path 指向 DLL 所在資料夾。
public class Main {
static {
System.loadLibrary("MakeDLL"); // 載入 DLL,不需副檔名
}
public native static int getStrNum(byte[] str, int strLen);
public static void main(String[] args) {
Main instance = new Main();
String str = "haha";
int num = instance.getStrNum(str.getBytes(), str.length());
System.out.println("字串長度: " + num); // 輸出 4
}
}
JNIEnv 指標操作。例如 GetByteArrayElements 取得陣列指標,SetByteArrayRegion 回寫資料。Get 系列函式通常會複製或釘住記憶體,用畢必須呼叫對應的 Release 函式。透過 JNI 整合 C/C++ 程式庫雖然增加了部署複雜度,但能發揮原生程式碼的高效能優勢。掌握標頭檔產生、專案設定、資料轉換與記憶體管理四大核心步驟,即可順利完成 Java 與本地程式碼的互操作。