初識JNA

1.JNA簡介java

      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 的數據類型映射。windows

2.JNA調用原生函數示例數組

      假設libCms.dll動態連接庫中發佈了以下C函數:app

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~255
	param.setCastMode(2);//播放方式,單播,組播和廣播[0,1,2]
	param.setVolume(80);//音量0~100
	param.setIP(3232261139L);//IP轉數字
	param.setTone(0);//音調(未使用)0~15
    param.setBass(200);//低音頻率0~3000
	param.setTreble(3000);//高音頻率200~20000
	param.setTrebleEn(0);//高音放大因子0~255
	param.setBassEn(0);//低音放大因子0~255
	param.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 的數據類型。而原生函數中使用的數據類型是原生函數的編程語言使用的數據類型。多是C,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 不能管理,會形成內存碎片。
若是在你須要調用的動態連接庫中,有複雜的數據類型和龐大的跨平臺數據傳遞。那麼
你應該另外寫一些原生函數,把須要傳遞的數據類型簡化,把須要傳遞的數據量簡化。

 

天天一道面試題,持續更新@目錄

相關文章
相關標籤/搜索