<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
JNA提供JAVA型別和native型別的對映關係,但是這一種對映關係只是一個大概的對映,我們在實際的應用中還有很多需要注意的事項,本文將會為大家詳細講解在使用型別對映中可能會出現的問題。一起來看看吧。
首先是String的對映,JAVA中的String實際上對應的是兩種native型別:const char* 和 const wchar_t*。預設情況下String會被轉換成為char* 。
char是ANSI型別的資料型別,而wchar_t是Unicode字元的資料型別,也叫做寬字元。
如果JAVA的unicode characters要轉換成為char陣列,那麼需要進行一些編碼操作,如果設定了jna.encoding,那麼就會使用設定好的編碼方式來進行編碼。預設情況下編碼方式是 “UTF8”.
如果是WString,那麼Unicode values可以直接拷貝到WString中,而不需要進行任何編碼。
先看一個簡單的例子:
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);
我們定義了兩個方法,方法的引數分別是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);
可能有同學會問了,既然JAVA中的String可以轉換成為char*,為什麼這裡需要使用byte陣列呢?
這是因為getString方法需要對傳入的char陣列中的內容進行修改,但是因為String是不可變的,所以這裡是不能直接使用String的,我們需要使用byte陣列。
接著我們使用Native.toString(byte[]) 將byte陣列轉換成為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進行對映:
// Mapping A String getString(); // Mapping B WString getString();
如果native code為String分配了記憶體空間,那麼我們最好使用JNA中的Pointer作為返回值,這樣我們可以在未來某些時候,釋放所佔用的空間,如下所示:
Pointer getString();
什麼時候需要用到Buffers和Memory呢?
一般情況下如果是基礎資料的陣列作為引數傳到函數中的話,可以在JAVA中直接使用基礎類的陣列來替代。但是如果native方法在方法返回之後,還需要存取陣列的話(儲存了指向陣列的指標),這種情況下使用基礎類的陣列就不太合適了,這種情況下,我們需要用到ByteBuffers或者Memory。
我們知道JAVA中的陣列是帶有長度的,但是對於native方法來說,返回的陣列實際上是一個指向陣列的指標,我們並不能知道返回陣列的長度,所以如果native方法返回的是陣列指標的話,JAVA程式碼中用陣列來進行對映就是不合適的。這種情況下,需要用到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);
再看一下字串陣列:
char* returnStringArrayElement(char* args[], int which) { return args[which]; } wchar_t* returnWideStringArrayElement(wchar_t* args[], int which) { return args[which]; }
對應的JAVA對映如下:
String returnStringArrayElement(String[] args, int which); WString returnWideStringArrayElement(WString[] args, int which);
對應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進行填充,很明顯後續還需要使用到這個buffer,所以這裡使用陣列是不合適的,我們可以選擇使用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)); }
對於native和JAVA本身來說,都是支援可變引數的,我們舉個例子,在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; }
對應的JAVA方法對映如下:
public int addVarArgs(String fmt, Number... args);
相應的呼叫程式碼如下:
int arg1 = 1; int arg2 = 2; assertEquals("32-bit integer varargs not added correctly", arg1 + arg2, lib.addVarArgs("dd", arg1, arg2));
本文介紹了在使用JNA方法對映中應該注意的一些細節和具體的使用問題。
本文的程式碼:https://github.com/ddean2009/learn-java-base-9-to-20.git
到此這篇關於java高階用法中的JNA型別對映應該注意的問題小結的文章就介紹到這了,更多相關java JNA型別對映內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45