博客中提到的JNI均指Java Native Interface,Java本地接口。本地代碼均指C/C++代碼。
JNI簡介
JNI是Java平臺中的一個非常強大的特性,通過JNI相關的接口,我們不僅可以在Java中調用本地代碼,也可以在本地代碼使用Java完成相關的操作,并且不需要考慮操作系統之間的差異。那么JNI是如何消除操作系統之間的差異的呢?首先,我們要理解兩個概念:Java平臺和主機環境。Java平臺是包含了Java虛擬機和Java API接口的編程環境,Java應用程序會被編譯成與機器無關的二進制格式的類文件,這些類文件能夠被Java虛擬機解析執行。主機環境表示主機操作系統,本地庫和計算機指令集。使用C/C++編寫的本地代碼會被編譯成與機器相關的二進制代碼并與本地庫鏈接起來。JRE(Java Runtime Environment)就是這樣的一個主機環境。Java應用程序、Java虛擬機、JNI、本地應用程序或者本地代碼庫與主機環境之間的關系如下圖所示:

Java應用程序在Java虛擬機里解析執行,Java虛擬機在主機環境里運行,并通過JNI接口與本地應用程序或者代碼庫進行通信。
JNI啟示
需要強調的一點是,一旦使用JNI去編寫應用程序就意味著你將失去Java平臺的兩個特性:
- Java應用程序不再跨平臺運行。即便Java語言編寫的部分是跨平臺的,但是你仍然需要將本地代碼部分重新編譯成與平臺相關的代碼;
- 本地代碼并不是類型安全的語言,然而Java卻是。因此,如果本地代碼稍有差錯都回導致Java虛擬機崩潰?;谶@一點,在執行JNI之前進行安全檢查是非常重要的一個步驟。
什么情況下使用JNI
在《JNI啟示》小節中介紹了使用JNI的兩個劣勢,使用JNI之前通常需要考慮是否還有其它方式來完成Java與不同語言之間的交互,下面是三種常見的不使用JNI的方式:
- TCP連接或者其它IPC機制;
- JDBC;
- Java IDL接口。
以上三種方式的共同特點是Java應用程序與本地代碼是在不同進程中運行的,因此,本地代碼的錯誤并不會引起Java虛擬機的崩潰。如果你需要Java應用程序與在同一進程內的本地代碼進行交互,那么JNI就派上用場了,比如以下幾種情況:
- Java API不支持與特定操作系統相關的特性;
- Java應用程序想要訪問本地代碼庫,但是想減少進程間通信的開銷;
- 使用本地代碼實現對性能要求非常高的功能。