native 方法。javac 編譯 → javah 產生 C/C++ 標頭檔 (.h)。.dll,置於 Java 類別路徑或 java.library.path。System.loadLibrary 載入並呼叫。public class Main {
// native 方法:傳入 byte[] 與長度,回傳字串長度
public native static int getStrNum(byte[] str, int strLen);
static {
// 載入 DLL(檔名不含副檔名)
System.loadLibrary("MakeDLL");
}
public static void main(String[] args) {
Main inst = new Main();
String test = "haha";
int len = inst.getStrNum(test.getBytes(), test.length());
System.out.println("Length: " + len); // 輸出 4
}
}
javac Main.java
javah Main
產生 Main.h,包含 JNI 函數原型:
JNIEXPORT jint JNICALL Java_Main_getStrNum
(JNIEnv *, jclass, jbyteArray, jint);
MakeDLL → Empty Project。$(JAVA_HOME)\include$(JAVA_HOME)\include\win32Main.h 加入專案。main.cpp 實作:#include "Main.h"
#include
JNIEXPORT jint JNICALL Java_Main_getStrNum
(JNIEnv *env, jclass cls, jbyteArray str, jint strLen) {
// 取得 byte[] 內容指標
jbyte *buf = (*env)->GetByteArrayElements(env, str, 0);
// 手動加結束符(Java 字串不保證以 \0 結尾)
buf[strLen] = '\0';
// 計算長度
jint len = strlen((char*)buf);
// 釋放陣列元素
(*env)->ReleaseByteArrayElements(env, str, buf, 0);
return len;
}
MakeDLL.dll。MakeDLL.dll 複製到 Main.class 同目錄,或設定 -Djava.library.path=.。java Main → 輸出 Length: 4。| 操作 | JNI 函數 | 說明 |
|---|---|---|
| 取得 primitive 陣列元素 | GetByteArrayElements, GetIntArrayElements, ... | 回傳 C 指標,用畢須 Release |
| 釋放陣列元素 | ReleaseByteArrayElements, ... | mode: 0=複製回寫, JNI_COMMIT=只寫回, JNI_ABORT=放棄修改 |
| 建立新陣列 | NewByteArray, NewIntArray, ... | 回傳 jarray |
| 設定陣列區域 | SetByteArrayRegion, ... | 從 C 緩衝區複製資料到 Java 陣列 |
| 字串轉換 | NewStringUTF, GetStringUTFChars | UTF-8 編碼互轉 |
UnsatisfiedLinkError:DLL 找不到、架構不符 (32/64-bit)、函數簽名不符(檢查 javah 產生的標頭)。Release...ArrayElements。(*env)->ThrowNew 或讓 Java 端捕捉。JNI 讓 Java 能重用 C/C++ 高效能庫或系統級 API,但增加了部署複雜度與風險。現代替代方案包括 JNA (Java Native Access)、JNR-FFI、或透過 gRPC/REST 進行進程間通訊,視情況選擇。