初识JNA
2019獨角獸企業重金招聘Python工程師標準>>>
1.JNA簡介
????? JNA(Java Native Access)框架是一個開源的Java 框架,是SUN 公司主導開發的,建立在經典的JNI 的基礎之上的一個框架。JNA 項目地址:https://jna.dev.java.net/。
????? JNI 是Java 調用原生函數唯一的機制。JNA 也是建立在JNI 技術之上的,它簡化了Java調用原生函數的過程。使用JNA可以使你像調用java方法一樣直接調用本地方法,極大地擴展了java平臺的整合能力。
????? JNA 提供了一個動態的C 語言編寫的轉發器,可以自動實現Java 和C 的數據類型映射。
2.JNA調用原生函數示例
????? 假設libCms.dll動態鏈接庫中發布了如下C函數:
lc_init(string filename,Param param)該函數作用是根據監聽參數啟動一個監聽,CmsListenParam具體是什么暫時不用管,后面會詳細介紹。為了調用這個原生函數,使用JNA,編寫如下java代碼:
private interface GetBroadcastIds extends Library {GetBroadcastIds INSTANCE = (GetBroadcastIds) Native.loadLibrary("LCAudioThrDll",GetBroadcastIds.class);int lc_init(String filename,Param param);}然后我們就可以像調用java代碼一樣調用原生函數了:
public static void main(String[] args) {String filename = "D:\\KuGou\\體面.mp3";Param param = new Param();param.sethWnd(0L);//Windows窗口句柄,如果不為NULL,線程將事件消息發送到此窗口param.setPriority(0);//音頻流優先級0~255param.setCastMode(2);//播放方式,單播,組播和廣播[0,1,2]param.setVolume(80);//音量0~100param.setIP(3232261139L);//IP轉數字param.setTone(0);//音調(未使用)0~15param.setBass(200);//低音頻率0~3000param.setTreble(3000);//高音頻率200~20000param.setTrebleEn(0);//高音放大因子0~255param.setBassEn(0);//低音放大因子0~255param.setSourcType(0);//音頻數據源,0表示數據源為文件,1表示數據源為聲卡輸入[0,1,2,3]DDMineService.instance.lc_init(filename,param);System.out.println("調用成功"); }3.JNA調用原生函數的模式
? ? JNA中使用Native關鍵字來聲明一個Java方法代表外部的原生函數,JNA不使用Native代表原生函數,而是使用java interface來代表動態鏈接庫中代表的所有原生函數,對于不使用的原生函數,可以不在interface中聲明原型。?
4.java和原生代碼的類型映射
????JNA 使用的數據類型是Java 的數據類型。而原生函數中使用的數據類型是原生函數的編程語言使用的數據類型??赡苁荂,Delphi,匯編等語言的數據類型。如數據類型映射不一致,在調用中可能會發生無法預知的行為,可能是調用不成功,也可能不能正確解析返回數據。????
????C#,java和操作系統數據類型對應表
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/u/4006148/blog/2252532
總結
- 上一篇: 数据预处理--样本选择、交叉验证
- 下一篇: 什么是网站权重?