1.JNA簡介java
JNA(Java Native Access)框架是一個開源的Java 框架,是SUN 公司主導開發的,創建在經典的JNI 的基礎之上的一個框架。JNA 項目地址:https://jna.dev.java.net/。編程
JNI 是Java 調用原生函數惟一的機制。JNA 也是創建在JNI 技術之上的,它簡化了Java調用原生函數的過程。使用JNA可使你像調用java方法同樣直接調用本地方法,極大地擴展了java平臺的整合能力。windows
JNA 提供了一個動態的C 語言編寫的轉發器,能夠自動實現Java 和C 的數據類型映射。數組
2.JNA調用原生函數示例app
假設libCms.dll動態連接庫中發佈了以下C函數:框架
LONG startListen(CmsListenParam listenPara);
該函數做用是根據監聽參數啓動一個監聽,CmsListenParam具體是什麼暫時不用管,後面會詳細介紹。爲了調用這個原生函數,使用JNA,編寫以下java代碼:編程語言
public interface CmsServer extends StdCallLibrary{ //根據dll名字加載庫文件 CmsServer instance=(CmsServer) Native.loadLibrary("libCms",CmsServer.class); NativeLong startListen(CmsListenParam listenPara); }
而後咱們就能夠像調用java代碼同樣調用原生函數了:函數
public static void main(String[] args) { CmsServer.instance.startListen(new CmsListenParam()); System.out.println("調用成功"); }
3.JNA調用原生函數的模式性能
JNI中使用Native關鍵字來聲明一個java方法表明外部的原生函數,JNA不使用Native表明原生函數,而是使用java interface來表明動態連接庫中表明的全部原生函數,對於不使用的原生函數,能夠不在interface中聲明原型。 spa
對於加載動態連接庫,若是使用JNI,須要使用System. loadLibrary 方法,把專爲JNI 編寫的動態連接庫載入進來。這個動態連接庫其實是咱們真正須要的動態連接庫的代理。若使用JNA,不須要編寫做爲代理的動態連接庫,使用JNA 類庫的Native 類的loadLibrary 方法直接把咱們須要的動態連接庫載入進來。
上面代碼中,使用了java單例模式,接口的靜態變量返回的是接口的惟一實例,該實例由JNA經過反射動態建立,經過這個對象,能夠調用動態連接庫發佈的全部函數。
4.java和原生代碼的類型映射
JNA 使用的數據類型是Java 的數據類型。而原生函數中使用的數據類型是原生函數的編程語言使用的數據類型。多是C,Delphi,彙編等語言的數據類型。如數據類型映射不一致,在調用中可能會發生沒法預知的行爲,多是調用不成功,也可能不能正確解析返回數據。
C,java和操做系統數據類型對應表
native type | size | java type | common windows types |
char | 8-bit integer |
byte | BYTE, TCHAR |
short | 16-bit integer | short | WORD |
wchar_t | 16/32-bit character | char | TCHAR |
int | 32-bit integer | int | DWORD |
int | boolean value | boolean | BOOL |
long | 32/64-bit integer | NativeLong | LONG |
long long | 64-bit integer | long | __int64 |
float | 32-bit FP | float | |
double | 64-bit FP | double | |
char* | C string | String | LPTCSTR |
void* | pointer | Pointer | LPVOID, HANDLE, LPXXX |
pointer | Buffer/Pointer | 平臺依賴(32 或64 位指針) | |
pointer/array | <T>[] (基本類型的數組) | 32 或64 位指針(參數/返回值) 鄰接內存(結構體成員) |
|
wchar_t* | WString | \0 結束的數組(unicode) | |
char** | String[] | \0 結束的數組的數組 | |
wchar_t** | WString[] | \0 結束的寬字符數組的數組 | |
struct*/struct | Structure | 指向結構體的指針(參數或返回值) (或者明確指定是結構體指針)/結構體(結構體的成員) (或者明確指定是結構體) | |
union | Union | 等同於結構體 | |
Structure[] | struct[] | 結構體的數組,鄰接內存 | |
<T> (*fp)() | Callback | Java 函數指針或原生函數指針 | |
varies | NativeMapped | 依賴於定義 | |
pointer | PointerType | 和Pointer 相同 |
5.跨平臺、跨語言調用原則:
儘可能使用基本、簡單的數據類型;
儘可能少跨平臺、跨語言傳遞數據!
若是有複雜的數據類型須要在Java 和原生函數中傳遞,那麼咱們就必須在Java 中模擬
大量複雜的原生類型。這將大大增長實現的難度,甚至沒法實現。
若是在Java 和原生函數間存在大量的數據傳遞,那麼一方面,性能會有很大的損失。
更爲重要的是,Java 調用原生函數時,會把數據固定在內存中,這樣原生函數才能夠訪問這
些Java 數據。這些數據,JVM 的GC 不能管理,會形成內存碎片。
若是在你須要調用的動態連接庫中,有複雜的數據類型和龐大的跨平臺數據傳遞。那麼
你應該另外寫一些原生函數,把須要傳遞的數據類型簡化,把須要傳遞的數據量簡化。
本小節到此結束,下一節將重點介紹結構體
歡迎指出本文有誤的地方,轉載請註明原文出處https://my.oschina.net/7001/blog/672283