Java 無法直接存取作業系統底層 (硬體、系統呼叫、舊有 C/C++ 庫)。JNI (Java Native Interface) 提供橋樑:Java 宣告 native 方法 → javah 產生 C 標頭檔 → C/C++ 實作 → 編譯為動態庫 → System.loadLibrary 載入。本文以「Hello World」為例,完整演示 Windows + Visual C++ 命令列編譯全流程。
package com.hode.hodeframework.modelupdate;
public class CheckFile {
public native void displayHelloWorld();
static {
System.loadLibrary("test"); // 載入 test.dll (Windows) / libtest.so (Linux)
}
public static void main(String[] args) {
new CheckFile().displayHelloWorld();
}
}
# 進入 class 輸出根目錄 (如 bin/ 或 classes/)
javac com/hode/hodeframework/modelupdate/CheckFile.java
javah -jni com.hode.hodeframework.modelupdate.CheckFile
# 產生 com_hode_hodeframework_modelupdate_CheckFile.h
// com_hode_hodeframework_modelupdate_CheckFile.c
#include "com_hode_hodeframework_modelupdate_CheckFile.h"
#include
JNIEXPORT void JNICALL
Java_com_hode_hodeframework_modelupdate_CheckFile_displayHelloWorld(
JNIEnv *env, jobject obj) {
printf("Hello world from C!\n");
return;
}
cl -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" \
-LD com_hode_hodeframework_modelupdate_CheckFile.c \
-Fe test.dll
-I:指定 JDK 標頭檔路徑 (jni.h, jni_md.h)-LD:建立 DLL-Fe:指定輸出檔名 (需與 `loadLibrary("test")` 一致)Linux/GCC 範例:
gcc -shared -fPIC -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/linux" \
com_hode_hodeframework_modelupdate_CheckFile.c -o libtest.so
java -Djava.library.path=. com.hode.hodeframework.modelupdate.CheckFile
# 輸出: Hello world from C!
| 主題 | 關鍵 API / 概念 |
|---|---|
| Java 物件操作 | GetFieldID, GetMethodID, CallVoidMethod, NewObject, Get/Set<Type>Field |
| 陣列處理 | GetArrayLength, Get<Type>ArrayElements, Release<Type>ArrayElements, New<Type>Array |
| 字串處理 | NewStringUTF, GetStringUTFChars, ReleaseStringUTFChars (注意 UTF-8/UTF-16 轉換) |
| 異常拋出 | ThrowNew, Throw, ExceptionCheck, ExceptionClear |
| 全域/區域引用 | NewGlobalRef, DeleteGlobalRef, NewLocalRef (防止 GC 回收 Native 持有的物件) |
| 線程附著 | AttachCurrentThread, DetachCurrentThread (非 Java 建立的線程呼叫 JNI 必須附著) |
除非極度依賴 JNI 細粒度控制,**新專案優先評估 JNA/JNR**,大幅降低維護成本。