Java 最大的優勢在於「一次編寫,到處執行」的跨平台特性,但這也成為雙面刃——當 Java 程式需要存取平台特定功能(如 Windows API、硬體驅動程式、既有的 C/C++ 函式庫)時,純 Java 無法直接完成。Java Native Interface (JNI) 正是解決這個問題的橋樑,它允許 Java 程式碼呼叫原生程式碼(C/C++),並反之亦然。
native 關鍵字宣告,實作邏輯寫在 C/C++ 中。static { System.loadLibrary("..."); } 在類別載入時將原生函式庫(.dll / .so)載入記憶體。public class JNITest {
static {
System.loadLibrary("JNITest"); // 載入 JNITest.dll (Windows) 或 libJNITest.so (Linux)
}
native void showMessage(String str); // 宣告 native 方法
public JNITest() {
System.out.println("In the constructor of the Java program");
}
public static void main(String[] args) {
JNITest test = new JNITest();
test.showMessage("Passing string from Java");
}
}
javac JNITest.java 產生 JNITest.classjavah -jni JNITest 產生 JNITest.h產生的標頭檔會包含如下函式簽名:
JNIEXPORT void JNICALL Java_JNITest_showMessage(JNIEnv *, jobject, jstring);
include 與 include/win32 目錄加入專案的 Include 路徑。jni.h 與剛產生的 JNITest.h。Java 字串(jstring)在 C++ 中需透過 JNIEnv 轉換為 C 風格字串,用畢必須釋放,否則會導致 JVM 記憶體洩漏甚至崩潰。
JNIEXPORT void JNICALL Java_JNITest_showMessage(
JNIEnv *env, jobject obj, jstring str) {
const char *cStr = env->GetStringUTFChars(str, 0); // 轉換
if (cStr == NULL) return; // 記憶體不足
MessageBox(0, cStr, "Message from VC++", 0); // 呼叫 Windows API
env->ReleaseStringUTFChars(str, cStr); // 釋放
}
JNITest.dll。java.library.path 指定路徑。java JNITest 即可看到 VC++ 彈出的訊息框。.h 檔一致。ReleaseStringUTFChars 導致 JVM Crash。JNI 雖強大,但增加了部署複雜度與平台相依性。建議僅在必要時(如呼叫 OS API、效能關鍵路徑、整合既有 C/C++ 資產)使用,並妥善封裝介面,維持 Java 端程式碼純粹性。