**JNI (Java Native Interface)** 是 Java 與本地代碼(C/C++)交互的橋樑。當 Java 難以勝任底層系統操作、高性能計算、硬體控制或需復用現有 C/C++ 庫時,JNI 允許 Java 代碼調用本地方法,極大擴展了 Java 的應用邊界。
目標:Java 傳入字串 `"world"`,C 函數在前面拼接 `"hello "` 並返回 `"hello world"`。
public class Test {
// 1. native 關鍵字聲明本地方法
public native String helloworld(String text);
public static void main(String[] args) {
// 2. 載入動態庫:Windows 對應 Test2.dll,Linux 對應 libTest2.so
System.loadLibrary("Test2");
Test ts = new Test();
String result = ts.helloworld("world");
System.out.println(result); // 輸出: hello world
}
}
> javac Test.java
// 生成 Test.class
> javah Test
// 生成 Test.h
生成的 `Test.h` 關鍵內容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Test */
#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Test
* Method: helloworld
* Signature: (Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Test_helloworld
(JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
#include "Test.h"
#include <string.h>
JNIEXPORT jstring JNICALL Java_Test_helloworld
(JNIEnv *env, jobject obj, jstring j_str) {
// 1. 將 Java 字串 (UTF-16) 轉為 C 字串 (UTF-8)
const char* c_str = (*env)->GetStringUTFChars(env, j_str, 0);
// 2. 構建結果字串
char buffer[128] = "hello "; // 預留空間
strcat(buffer, c_str); // 拼接
// 3. 釋放 GetStringUTFChars 分配的內存(關鍵!防內存洩漏)
(*env)->ReleaseStringUTFChars(env, j_str, c_str);
// 4. 將 C 字串轉為 Java 字串返回
return (*env)->NewStringUTF(env, buffer);
}
關鍵 JNI 字串函數對照表:
| 函數 | 用途 | 注意事項 |
|---|---|---|
| `GetStringUTFChars` | Java String → C `const char*` (UTF-8) | 必須配對調用 `ReleaseStringUTFChars` 釋放 |
| `ReleaseStringUTFChars` | 釋放上述分配的內存 | 忘記調用導致 Native 內存洩漏 |
| `NewStringUTF` | C `const char*` (UTF-8) → Java String | 返回局部引用,若長期持有需轉全局引用 |
Windows (MinGW/GCC):
> gcc -I "C:\Program Files\Java\jdk1.8.0_45\include" \
-I "C:\Program Files\Java\jdk1.8.0_45\include\win32" \
-shared Test2.c -o Test2.dll
Linux (GCC):
$ gcc -I /usr/lib/jvm/java-8-openjdk/include \
-I /usr/lib/jvm/java-8-openjdk/include/linux \
-fPIC -shared Test2.c -o libTest2.so
> java Test
// 輸出: hello world
對於新項目,優先考慮:
JNI 仍是理解 Java 底層互操作的基石,掌握其原理有助於排查疑難雜症與評估技術選型。