最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

教你在JNA中將本地方法映射到JAVA代碼中的示例

 更新時(shí)間:2022年04月13日 15:01:18   作者:flydean程序那些事  
對(duì)于JNI來(lái)說(shuō),我們可以使用native關(guān)鍵字來(lái)定義本地方法。那么在JNA中有那些在JAVA代碼中定義本地方法的方式呢?對(duì)JNA本地方法映射JAVA代碼的相關(guān)知識(shí)感興趣的朋友一起看看吧

簡(jiǎn)介

不管是JNI還是JNA,最終調(diào)用的都是native的方法,但是對(duì)于JAVA程序來(lái)說(shuō),一定需要一個(gè)調(diào)用native方法的入口,也就是說(shuō)我們需要在JAVA方法中定義需要調(diào)用的native方法。

對(duì)于JNI來(lái)說(shuō),我們可以使用native關(guān)鍵字來(lái)定義本地方法。那么在JNA中有那些在JAVA代碼中定義本地方法的方式呢?

Library Mapping

要想調(diào)用本地的native方法,首選需要做的事情就是加載native的lib文件。我們把這個(gè)過(guò)程叫做Library Mapping,也就是說(shuō)把native的library 映射到j(luò)ava代碼中。

JNA中有兩種Library 映射的方法,分別是interface和direct mapping。

先看下interface mapping,假如我們要加載 C library, 如果使用interface mapping的方式,我們需要?jiǎng)?chuàng)建一個(gè)interface繼承Library:

public interface CLibrary extends Library {
    CLibrary INSTANCE = (CLibrary)Native.load("c", CLibrary.class);
}

上面代碼中Library是一個(gè)interface,所有的interface mapping都需要繼承這個(gè)Library。

然后在interface內(nèi)部,通過(guò)使用Native.load方法來(lái)加載要使用的c library。

上面的代碼中,load方法傳入兩個(gè)參數(shù),第一個(gè)參數(shù)是library的name,第二個(gè)參數(shù)是interfaceClass.

下面的表格展示了Library Name和傳入的name之間的映射關(guān)系:

OSLibrary NameString
Windowsuser32.dlluser32
LinuxlibX11.soX11
Mac OS Xlibm.dylibm
Mac OS X Framework/System/Library/Frameworks/Carbon.framework/CarbonCarbon
Any Platformcurrent processnull

事實(shí)上,load還可以接受一個(gè)options的Map參數(shù)。默認(rèn)情況下JAVA interface中要調(diào)用的方法名稱就是native library中定義的方法名稱,但是有些情況下我們可能需要在JAVA代碼中使用不同的名字,在這種情況下,可以傳入第三個(gè)參數(shù)map,map的key可以是 OPTION_FUNCTION_MAPPER,而它的value則是一個(gè) FunctionMapper ,用來(lái)將JAVA中的方法名稱映射到native library中。

傳入的每一個(gè)native library都可以用一個(gè)NativeLibrary的實(shí)例來(lái)表示。這個(gè)NativeLibrary的實(shí)例也可以通過(guò)調(diào)用NativeLibrary.getInstance(String)來(lái)獲得。

另外一種加載native libary的方式就是direct mapping,direct mapping使用的是在static block中調(diào)用Native.register方式來(lái)加載本地庫(kù),如下所示:

public class CLibrary {
    static {
        Native.register("c");
    }
}

Function Mapping

當(dāng)我們加載完native library之后,接下來(lái)就是定義需要調(diào)用的函數(shù)了。實(shí)際上就是做一個(gè)從JAVA代碼到native lib中函數(shù)的一個(gè)映射,我們將其稱為Function Mapping。

和Library Mapping一樣,F(xiàn)unction Mapping也有兩種方式。分別是interface mapping和direct mapping。

在interface mapping中,我們只需要按照native library中的方法名稱定義一個(gè)一樣的方法即可,這個(gè)方法不用實(shí)現(xiàn),也不需要像JNI一樣使用native來(lái)修飾,如下所示:

public interface CLibrary extends Library {
    int atol(String s);
}

注意,上面我們提到了JAVA中的方法名稱不一定必須和native library中的方法名稱一致,你可以通過(guò)給Native.load方法傳入一個(gè)FunctionMapper來(lái)實(shí)現(xiàn)。

或者,你可以使用direct mapping的方式,通過(guò)給方法添加一個(gè)native修飾符:

public class HelloWorld {
            
    public static native double cos(double x);
    public static native double sin(double x);
    
    static {
        Native.register(Platform.C_LIBRARY_NAME);
    }

    public static void main(String[] args) {
        System.out.println("cos(0)=" + cos(0));
        System.out.println("sin(0)=" + sin(0));
    }
}

對(duì)于direct mapping來(lái)說(shuō),JAVA方法可以映射到native library中的任何static或者對(duì)象方法。

雖然direct mapping和我們常用的java JNI有些類(lèi)似,但是direct mapping存在著一些限制。

大部分情況下,direct mapping和interface mapping具有相同的映射類(lèi)型,但是不支持Pointer/Structure/String/WString/NativeMapped數(shù)組作為函數(shù)參數(shù)值。

在使用TypeMapper或者NativeMapped的情況下,direct mapping不支持 NIO Buffers 或者基本類(lèi)型的數(shù)組作為返回值。

如果要使用基礎(chǔ)類(lèi)型的包裝類(lèi),則必須使用自定義的TypeMapper.

對(duì)象JAVA中的方法映射來(lái)說(shuō),該映射最終會(huì)創(chuàng)建一個(gè)Function對(duì)象。

Invocation Mapping

講完library mapping和function mapping之后,我們接下來(lái)講解一下Invocation Mapping。

Invocation Mapping代表的是Library中的OPTION_INVOCATION_MAPPER,它對(duì)應(yīng)的值是一個(gè)InvocationMapper。

之前我們提到了FunctionMapper,可以實(shí)現(xiàn)JAVA中定義的方法名和native lib中的方法名不同,但是不能修改方法調(diào)用的狀態(tài)或者過(guò)程。

而InvocationMapper則更進(jìn)一步, 允許您任意重新配置函數(shù)調(diào)用,包括更改方法名稱以及重新排序、添加或刪除參數(shù)。

下面舉個(gè)例子:

   new InvocationMapper() {
       public InvocationHandler getInvocationHandler(NativeLibrary lib, Method m) {
           if (m.getName().equals("stat")) {
               final Function f = lib.getFunction("_xstat");
               return new InvocationHandler() {
                   public Object invoke(Object proxy, Method method, Object[] args) {
                       Object[] newArgs = new Object[args.length+1];
                       System.arraycopy(args, 0, newArgs, 1, args.length);
                       newArgs[0] = Integer.valueOf(3); // _xstat version
                       return f.invoke(newArgs);
                   }
               };
           }
           return null;
       }
   }

看上面的調(diào)用例子,感覺(jué)有點(diǎn)像是反射調(diào)用,我們?cè)贗nvocationMapper中實(shí)現(xiàn)了getInvocationHandler方法,根據(jù)給定的JAVA代碼中的method去查找具體的native lib,然后獲取到lib中的function,最后調(diào)用function的invoke方法實(shí)現(xiàn)方法的最終調(diào)用。

在這個(gè)過(guò)程中,我們可以修改方傳入的參數(shù),或者做任何我們想做的事情。

還有一種情況是c語(yǔ)言中的內(nèi)聯(lián)函數(shù)或者預(yù)處理宏,如下所示:

// Original C code (macro and inline variations)
   #define allocblock(x) malloc(x * 1024)
   static inline void* allocblock(size_t x) { return malloc(x * 1024); }

上面的代碼中定義了一個(gè)allocblock(x)宏,它實(shí)際上等于malloc(x * 1024),這種情況就可以使用InvocationMapper,將allocblock使用具體的malloc來(lái)替換:

   // Invocation mapping
   new InvocationMapper() {
       public InvocationHandler getInvocationHandler(NativeLibrary lib, Method m) {
           if (m.getName().equals("allocblock")) {
               final Function f = lib.getFunction("malloc");
               return new InvocationHandler() {
                   public Object invoke(Object proxy, Method method, Object[] args) {
                       args[0] = ((Integer)args[0]).intValue() * 1024;
                       return f.invoke(newArgs);
                   }
               };
           }
           return null;
       }
   }

防止VM崩潰

JAVA方法和native方法映射肯定會(huì)出現(xiàn)一些問(wèn)題,如果映射方法不對(duì)或者參數(shù)不匹配的話,很有可能出現(xiàn)memory access errors,并且可能會(huì)導(dǎo)致VM崩潰。

通過(guò)調(diào)用Native.setProtected(true),可以將VM崩潰轉(zhuǎn)換成為對(duì)應(yīng)的JAVA異常,當(dāng)然,并不是所有的平臺(tái)都支持protection,如果平臺(tái)不支持protection,那么Native.isProtected()會(huì)返回false。

如果要使用protection,還要同時(shí)使用 jsig library,以防止信號(hào)和JVM的信號(hào)沖突。libjsig.so一般存放在JRE的lib目錄下, j a v a . h o m e / l i b / {java.home}/lib/ java.home/lib/{os.arch}/libjsig.so, 可以通過(guò)將環(huán)境變量設(shè)置為L(zhǎng)D_PRELOAD (或者LD_PRELOAD_64)來(lái)使用。

性能考慮

上面我們提到了JNA的兩種mapping方式,分別是interface mapping和direct mapping。相較而言,direct mapping的效率更高,因?yàn)閐irect mapping調(diào)用native方法更加高效。

但是上面我們也提到了direct mapping在使用上有一些限制,所以我們?cè)谑褂玫臅r(shí)候需要進(jìn)行權(quán)衡。

另外,我們需要避免使用基礎(chǔ)類(lèi)型的封裝類(lèi),因?yàn)閷?duì)于native方法來(lái)說(shuō),只有基礎(chǔ)類(lèi)型的匹配,如果要使用封裝類(lèi),則必須使用Type mapping,從而造成性能損失。

總結(jié)

JNA是調(diào)用native方法的利器,如果數(shù)量掌握的話,肯定是如虎添翼。

到此這篇關(guān)于教你在JNA中將本地方法映射到JAVA代碼中的文章就介紹到這了,更多相關(guān)JNA本地方法映射JAVA代碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot整合GitLab-CI實(shí)現(xiàn)持續(xù)集成的過(guò)程

    SpringBoot整合GitLab-CI實(shí)現(xiàn)持續(xù)集成的過(guò)程

    這篇文章主要介紹了SpringBoot整合GitLab-CI實(shí)現(xiàn)持續(xù)集成,本文詳細(xì)講述了 GitLab-CI 持續(xù)集成的安裝、部署、以及配置,需要的朋友可以參考下
    2022-12-12
  • feign 如何獲取請(qǐng)求真實(shí)目的ip地址

    feign 如何獲取請(qǐng)求真實(shí)目的ip地址

    這篇文章主要介紹了feign 獲取請(qǐng)求真實(shí)目的ip地址操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java socket字節(jié)流傳輸示例解析

    Java socket字節(jié)流傳輸示例解析

    這篇文章主要為大家詳細(xì)介紹了Java socket字節(jié)流傳輸示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • Javaweb mybatis接口開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解

    Javaweb mybatis接口開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解

    這篇文章主要介紹了Javaweb mybatis接口開(kāi)發(fā)實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • SpringBoot中接收POST參數(shù)的幾種方式詳解

    SpringBoot中接收POST參數(shù)的幾種方式詳解

    這篇文章主要介紹了SpringBoot中接收POST參數(shù)的幾種方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • springboot 配置使用swagger2操作

    springboot 配置使用swagger2操作

    這篇文章主要介紹了springboot 配置使用swagger2操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • Java枚舉_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java枚舉_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    enum 的全稱為 enumeration, 是 JDK 5 中引入的新特性,存放在 java.lang 包中。這篇文章給大家介紹Java枚舉相關(guān)知識(shí),需要的的朋友參考下
    2017-04-04
  • 詳解Java的MyBatis框架中動(dòng)態(tài)SQL的基本用法

    詳解Java的MyBatis框架中動(dòng)態(tài)SQL的基本用法

    這篇文章主要介紹了詳解Java的MyBatis框架中動(dòng)態(tài)SQL的基本用法,文中列出了一些常用SQL動(dòng)態(tài)語(yǔ)句進(jìn)行講解,需要的朋友可以參考下
    2016-04-04
  • Java中常用修飾符的使用方法匯總

    Java中常用修飾符的使用方法匯總

    下面小編就為大家?guī)?lái)一篇Java中常用修飾符的使用方法匯總。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-01-01
  • Java正則表達(dá)式API邊界匹配

    Java正則表達(dá)式API邊界匹配

    這篇文章主要介紹了Java正則表達(dá)式API邊界匹配,文章圍繞主題展開(kāi)相應(yīng)的相關(guān)資料,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2022-06-06

最新評(píng)論

宕昌县| 临泽县| 公主岭市| 湖州市| 宁明县| 崇左市| 托克逊县| 江阴市| 闵行区| 额尔古纳市| 姜堰市| 肇庆市| 徐汇区| 天镇县| 石屏县| 卢氏县| 原平市| 咸阳市| 通渭县| 珠海市| 涞水县| 富顺县| 桓台县| 榆树市| 叙永县| 大宁县| 苍梧县| 吴忠市| 桑日县| 牡丹江市| 黑龙江省| 武功县| 通化县| 广宁县| 大竹县| 保定市| 锦州市| 垦利县| 沂南县| 罗江县| 米脂县|