Java Native Interface (JNI) 歷來是 Java 調用本地代碼的標準橋樑,但它的使用體驗往往令人頭疼。根據 JEP 191 的分析,JNI 的主要痛點在於:強迫開發者編寫 C/C++ 代碼、需要深入理解 JVM 內存模型、跨平台編譯部署困難、性能開銷大,且構成了一個不透明的安全邊界。為了解決這些問題,社區孕育出了 JNA (Java Native Access) 和 JNR (Java Native Runtime) 等庫。JNR 由 JRuby 團隊主導開發,提供了更豐富的抽象層次、函數與內存元數據支持,並被視為未來 JEP 191 定義的標準 Foreign Function Interface (FFI) 的有力候選基礎。掌握 JNR,是為未來 Java 原生互操作做準備。
JNR 專案託管於 GitHub,採用 Maven 管理。直接下載 Zip 源碼或使用 Maven 中央倉庫的舊版本往往會導致依賴缺失,構建出的 JAR 無法使用。必須從源碼構建「Fat JAR」(包含所有依賴的全量包)。
git clone https://github.com/jnr/jnr-ffi.git,而非網頁下載 Zip。https://download.eclipse.org/technology/m2e/releases 安裝 m2eclipse。Import > Existing Maven Projects,指向克隆的根目錄。pom.xml 的 <plugins> 外層包裹 <pluginManagement> 標籤即可解決生命周期映射缺失問題。private final Native factory; 修正為 private final Native<T> factory;,構造函數同理。Build Fat JAR Eclipse 插件,右鍵專案選擇 Build Fat JAR,一鍵生成包含所有依賴的可用 JAR 包。pom.xml,在 <plugins> 區塊添加 maven-assembly-plugin 配置:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
mvn assembly:assembly。target/ 目錄下獲得 jnr-ffi-2.0.0-SNAPSHOT-jar-with-dependencies.jar,即為所需完整包。提示:若構建過程遇阻,文末提供了作者預構建的 JAR 下載鏈接作為備選。
將構建好的 JAR 加入專案類路徑。以下示例調用 C 標準庫 msvcrt.dll (Windows) 或 libc.so (Linux) 中的 puts() 函數。
package helloworld;
import jnr.ffi.LibraryLoader;
public class HelloWorld {
// 1. 定義一個靜態接口,映射目標本地函數
public static interface LibC {
int puts(String s);
}
public static void main(String[] args) {
// 2. 通過 LibraryLoader 加載庫並獲取接口實例
LibC libc = LibraryLoader.create(LibC.class).load("msvcrt"); // Linux 上填 "c"
// 3. 直接像調用 Java 方法一樣調用本地函數
libc.puts("Hello, World from JNR!");
}
}
LibraryLoader.create(Interface.class).load("libName")。庫名不帶前綴(lib)和後綴(.dll/.so/.dylib),JNR 會自動按平台解析。| Java 類型 | Native 類型 |
|---|---|
| byte | int8_t |
| short | int16_t |
| int | int32_t |
| long | intptr_t (平台相關 32/64 位) |
| float | float |
| double | double |
| String | const char * (UTF-8) |
| Pointer / Buffer | void * |
JNR 以純 Java 方式實現了高性能、類型安全的本地互操作,避免了 JNI 的樣板代碼與 C 編譯工具鏈依賴。隨著 Panama 專案 (JEP 191/419/422 等) 的推進,基於 JNR 架構的標準 FFI 終將內建於 JDK。提前掌握 JNR,不僅能解決當下的調用難題,更是對未來 Java 原生互操作標準的預演。