JNI簡介
JNI(Java Native Interface)是Java編程語言中用于實現Java代碼與本地(Native)代碼(通常是C或C++代碼)交互的機制。它允許Java應用程序調用本地代碼中的功能,也可以讓本地代碼調用Java類和方法。JNI在Java平臺上實現了Java與其他編程語言的互操作性。(即可互相調用)
主要目的和用途:
- 訪問本地功能: JNI允許Java程序通過調用本地代碼來訪問底層系統功能、硬件功能或第三方庫,這些本地代碼通常用C或C++編寫。
- 性能優化: 有時候,一些計算密集型任務在本地代碼中執行可能比在Java中更高效。通過JNI,你可以將這些任務放在本地代碼中,以提高性能。
- 平臺特定功能: JNI允許Java程序在需要平臺特定功能的情況下,通過本地代碼調用這些功能,以適應不同的操作系統和硬件環境。
- 復用現有代碼: 如果已經存在C/C++代碼庫,可以通過JNI將這些庫集成到Java應用程序中,而無需重新實現相同的功能。
基本流程:
- 編寫本地代碼: 首先,你需要編寫C/C++代碼實現要調用的功能。
- 生成動態庫: 將C/C++代碼編譯成動態鏈接庫(.dll或.so文件),供Java代碼調用。
- Java接口定義: 在Java中,你需要編寫一個與本地代碼對應的JNI接口,這樣Java代碼就能夠調用本地功能。
- 加載本地庫: 在Java代碼中使用System.loadLibrary("libraryName")加載本地庫。
- 調用本地功能: 通過JNI接口調用本地代碼,執行相應的功能。
- 資源管理: 注意JNI中需要管理內存和資源,防止內存泄漏和資源泄漏。
需要注意的是,使用JNI涉及到一些底層的編程技巧,以及對內存管理、線程安全等問題的處理。不當的使用可能會導致性能問題和安全隱患。
2 基本概念描述
2.1 基本數據類型
JNI 對于 Java 的基礎數據類型(int 等)和引用數據類型(Object、Class、數組等)的處理方式不同。這個原理非常重要,理解這個原理才能理解后面所有 JNI 函數的設計思路:
基礎數據類型: 會直接轉換為 C/C++ 的基礎數據類型,例如 int 類型映射為 jint 類型。由于 jint 是 C/C++ 類型,所以可以直接當作普通 C/C++ 變量使用,而不需要依賴 JNIEnv 環境對象;
引用數據類型: 對象只會轉換為一個 C/C++ 指針,例如 Object 類型映射為 jobject 類型。由于指針指向 Java 虛擬機內部的數據結構,所以不可能直接在 C/C++ 代碼中操作對象,而是需要依賴 JNIEnv 環境對象。另外,為了避免對象在使用時突然被回收,在本地方法返回前,虛擬機會固定(pin)對象,阻止其 GC。(參考demo中的multipleArray函數實現)
另外需要特別注意一點,基礎數據類型在映射時是直接映射,而不會發生數據格式轉換。例如,Java char 類型在映射為 jchar 后舊是保持 Java 層的樣子,數據長度依舊是 2 個字節,而字符編碼依舊是 UNT-16 編碼。
以下為Java類型與JNI類型的映射關系表,C++開發人員需要特別注意表中byte與char的區別。
Java類型 | JNI類型 | 描述 | 長度(字節) |
---|---|---|---|
boolean | jboolean | unsinged char | 1 |
byte | jbyte | signed char | 1 |
char | jchar | unsinged short | 2 |
short | jshort | signed short | 2 |
int | jint, jsize | signed int | 4 |
long | jlong | signed long | 8 |
float | jfloat | signed float | 4 |
double | jdouble | signed double | 8 |
Class | jclass | Class類 | / |
String | jstring | 字符串類 | / |
Object | jobject | 所有java類的父類 | / |
Throwable | jthrowable | 異常對象 | / |
boolean[] | jbooleanArray | 布爾數組 | / |
byte[] | jbyteArray | byte數組 | / |
char[] | jcharArray | char數組 | / |
s |