Java高級用法中的JNA類型映射注意細(xì)節(jié)及使用問題
簡介
JNA提供JAVA類型和native類型的映射關(guān)系,但是這一種映射關(guān)系只是一個大概的映射,我們在實際的應(yīng)用中還有很多需要注意的事項,本文將會為大家詳細(xì)講解在使用類型映射中可能會出現(xiàn)的問題。一起來看看吧。
String
首先是String的映射,JAVA中的String實際上對應(yīng)的是兩種native類型:const char* 和 const wchar_t*。默認(rèn)情況下String會被轉(zhuǎn)換成為char* 。
char是ANSI類型的數(shù)據(jù)類型,而wchar_t是Unicode字符的數(shù)據(jù)類型,也叫做寬字符。
如果JAVA的unicode characters要轉(zhuǎn)換成為char數(shù)組,那么需要進(jìn)行一些編碼操作,如果設(shè)置了jna.encoding,那么就會使用設(shè)置好的編碼方式來進(jìn)行編碼。默認(rèn)情況下編碼方式是 “UTF8”.
如果是WString,那么Unicode values可以直接拷貝到WString中,而不需要進(jìn)行任何編碼。
先看一個簡單的例子:
char* returnStringArgument(char *arg) {
return arg;
}
wchar_t* returnWStringArgument(wchar_t *arg) {
return arg;
}
上面的native代碼可以映射為:
String returnStringArgument(String s); WString returnWStringArgument(WString s);
再來看一個不同的例子,假如native方法的定義是這樣的:
int getString(char* buffer, int bufsize); int getUnicodeString(wchar_t* buffer, int bufsize);
我們定義了兩個方法,方法的參數(shù)分別是char* 和wchar_t*。
接下來看一下怎么在JAVA中定義方法的映射:
// Mapping A: int getString(byte[] buf, int bufsize); // Mapping B: int getUnicodeString(char[] buf, int bufsize);
下面是具體的使用:
byte[] buf = new byte[256]; int len = getString(buf, buf.length); String normalCString = Native.toString(buf); String embeddedNULs = new String(buf, 0, len);
可能有同學(xué)會問了,既然JAVA中的String可以轉(zhuǎn)換成為char*,為什么這里需要使用byte數(shù)組呢?
這是因為getString方法需要對傳入的char數(shù)組中的內(nèi)容進(jìn)行修改,但是因為String是不可變的,所以這里是不能直接使用String的,我們需要使用byte數(shù)組。
接著我們使用Native.toString(byte[]) 將byte數(shù)組轉(zhuǎn)換成為JAVA字符串。
再看一個返回值的情況:
// Example A: Returns a C string directly const char* getString(); // Example B: Returns a wide character C string directly const wchar_t* getString();
一般情況下,如果是native方法直接返回string,我們可以使用String進(jìn)行映射:
// Mapping A String getString(); // Mapping B WString getString();
如果native code為String分配了內(nèi)存空間,那么我們最好使用JNA中的Pointer作為返回值,這樣我們可以在未來某些時候,釋放所占用的空間,如下所示:
Pointer getString();
Buffers,Memory,數(shù)組和Pointer
什么時候需要用到Buffers和Memory呢?
一般情況下如果是基礎(chǔ)數(shù)據(jù)的數(shù)組作為參數(shù)傳到函數(shù)中的話,可以在JAVA中直接使用基礎(chǔ)類的數(shù)組來替代。但是如果native方法在方法返回之后,還需要訪問數(shù)組的話(保存了指向數(shù)組的指針),這種情況下使用基礎(chǔ)類的數(shù)組就不太合適了,這種情況下,我們需要用到ByteBuffers或者M(jìn)emory。
我們知道JAVA中的數(shù)組是帶有長度的,但是對于native方法來說,返回的數(shù)組實際上是一個指向數(shù)組的指針,我們并不能知道返回數(shù)組的長度,所以如果native方法返回的是數(shù)組指針的話,JAVA代碼中用數(shù)組來進(jìn)行映射就是不合適的。這種情況下,需要用到Pointer.
Pointer表示的是一個指針,先看一下Pointer的例子,首先是native代碼:
void* returnPointerArgument(void *arg) {
return arg;
}
void* returnPointerArrayElement(void* args[], int which) {
return args[which];
}接下來是JAVA的映射:
Pointer returnPointerArgument(Pointer p); Pointer returnPointerArrayElement(Pointer[] args, int which);
除了基本的Pointer之外,你還可以自定義帶類型的Pointer,也就是PointerType. 只需要繼承PointerType即可,如下所示:
public static class TestPointerType extends PointerType {
public TestPointerType() { }
public TestPointerType(Pointer p) { super(p); }
}
TestPointerType returnPointerArrayElement(TestPointerType[] args, int which);再看一下字符串?dāng)?shù)組:
char* returnStringArrayElement(char* args[], int which) {
return args[which];
}
wchar_t* returnWideStringArrayElement(wchar_t* args[], int which) {
return args[which];
}對應(yīng)的JAVA映射如下:
String returnStringArrayElement(String[] args, int which); WString returnWideStringArrayElement(WString[] args, int which);
對應(yīng)Buffer來說,JAVA NIO中提供了很多類型的buffer,比如ByteBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer和DoubleBuffer等。這里以ByteBuffer為例,來看一下具體的使用.
首先看下native代碼:
int32_t fillInt8Buffer(int8_t *buf, int len, char value) {
int i;
for (i=0;i < len;i++) {
buf[i] = value;
}
return len;
}這里將buff進(jìn)行填充,很明顯后續(xù)還需要使用到這個buffer,所以這里使用數(shù)組是不合適的,我們可以選擇使用ByteBuffer:
int fillInt8Buffer(ByteBuffer buf, int len, byte value);
然后看下具體怎么使用:
TestLibrary lib = Native.load("testlib", TestLibrary.class);
ByteBuffer buf = ByteBuffer.allocate(1024).order(ByteOrder.nativeOrder());
final byte MAGIC = (byte)0xED;
lib.fillInt8Buffer(buf, 1024, MAGIC);
for (int i=0;i < buf.capacity();i++) {
assertEquals("Bad value at index " + i, MAGIC, buf.get(i));
}可變參數(shù)
對于native和JAVA本身來說,都是支持可變參數(shù)的,我們舉個例子,在native方法中:
int32_t addVarArgs(const char *fmt, ...) {
va_list ap;
int32_t sum = 0;
va_start(ap, fmt);
while (*fmt) {
switch (*fmt++) {
case 'd':
sum += va_arg(ap, int32_t);
break;
case 'l':
sum += (int) va_arg(ap, int64_t);
break;
case 's': // short (promoted to 'int' when passed through '...')
case 'c': // byte/char (promoted to 'int' when passed through '...')
sum += (int) va_arg(ap, int);
break;
case 'f': // float (promoted to ‘double' when passed through ‘...')
case 'g': // double
sum += (int) va_arg(ap, double);
break;
default:
break;
}
}
va_end(ap);
return sum;
}對應(yīng)的JAVA方法映射如下:
public int addVarArgs(String fmt, Number... args);
相應(yīng)的調(diào)用代碼如下:
int arg1 = 1;
int arg2 = 2;
assertEquals("32-bit integer varargs not added correctly", arg1 + arg2,
lib.addVarArgs("dd", arg1, arg2));總結(jié)
本文介紹了在使用JNA方法映射中應(yīng)該注意的一些細(xì)節(jié)和具體的使用問題。
本文的代碼:https://github.com/ddean2009/learn-java-base-9-to-20.git
到此這篇關(guān)于java高級用法中的JNA類型映射應(yīng)該注意的問題小結(jié)的文章就介紹到這了,更多相關(guān)java JNA類型映射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
全網(wǎng)最精細(xì)詳解二叉樹,2萬字帶你進(jìn)入算法領(lǐng)域
大家好,我是哪吒,一個熱愛編碼的Java工程師,本著"欲速則不達(dá),欲達(dá)則欲速"的學(xué)習(xí)態(tài)度,在程序猿這條不歸路上不斷成長,所謂成長,不過是用時間慢慢擦亮你的眼睛,少時看重的,年長后卻視若鴻毛,少時看輕的,年長后卻視若泰山,成長之路,亦是漸漸放下執(zhí)念,內(nèi)心歸于平靜的旅程2021-08-08
使用@Autowired注解警告Field injection is not recommended的解決
這篇文章主要介紹了使用@Autowired注解警告Field injection is not recommended的解決,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
關(guān)于Java中static關(guān)鍵字的用法
這篇文章主要介紹了關(guān)于Java中static關(guān)鍵字的用法,static:意為靜態(tài)的,在?Java?里面作為靜態(tài)修飾符,可以理解為全局的意思,static?不僅可以修飾成員變量,成員方法,還可以修飾代碼塊,需要的朋友可以參考下2023-08-08
Java從JDK源碼角度對Object進(jìn)行實例分析
這篇文章主要介紹了Java從JDK源碼角度對Object進(jìn)行實例分析,具有一定借鑒價值,需要的朋友可以參考下。2017-12-12
解決spring boot網(wǎng)關(guān)gateway導(dǎo)致的坑,無法下載文件問題
這篇文章主要介紹了解決spring boot網(wǎng)關(guān)gateway導(dǎo)致的坑,無法下載文件的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07

