java native java高级用法之:在JNA中将本地方法映射到JAVA代码中

java native java高级用法之:在JNA中将本地方法映射到JAVA代码中

简介

不管是JNI还是JNA,最终调用的都是的方法,但是对于JAVA程序来说,一定需要一个调用方法的入口,也就是说我们需要在JAVA方法中定义需要调用的方法。

对于JNI来说,我们可以使用关键字来定义本地方法。那么在JNA中有那些在JAVA代码中定义本地方法的方式呢?

要想调用本地的方法,首选需要做的事情就是加载的lib文件。我们把这个过程叫做 ,也就是说把的 映射到java代码中。

JNA中有两种 映射的方法,分别是和 。

先看下 ,假如我们要加载 C , 如果使用 的方式,我们需要创建一个继承:

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

上面代码中是一个,所有的 都需要继承这个。

然后在内部,通过使用.load方法来加载要使用的c 。

上面的代码中,load方法传入两个参数,第一个参数是的name,第二个参数是.

下面的表格展示了 Name和传入的name之间的映射关系:

事实上,load还可以接受一个的Map参数。默认情况下JAVA 中要调用的方法名称就是 中定义的方法名称,但是有些情况下我们可能需要在JAVA代码中使用不同的名字,在这种情况下,可以传入第三个参数map,map的key可以是 ER,而它的value则是一个,用来将JAVA中的方法名称映射到 中。

传入的每一个 都可以用一个的实例来表示。这个的实例也可以通过调用.()来获得。

另外一种加载 的方式就是 , 使用的是在 block中调用.方式来加载本地库,如下所示:

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

当我们加载完 之后java native,接下来就是定义需要调用的函数了。实际上就是做一个从JAVA代码到 lib中函数的一个映射,我们将其称为 。

和 一样, 也有两种方式。分别是 和 。

在 中,我们只需要按照 中的方法名称定义一个一样的方法即可java native java高级用法之:在JNA中将本地方法映射到JAVA代码中,这个方法不用实现,也不需要像JNI一样使用来修饰,如下所示:

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

注意,上面我们提到了JAVA中的方法名称不一定必须和 中的方法名称一致,你可以通过给.load方法传入一个来实现。

或者,你可以使用 的方式,通过给方法添加一个修饰符:

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));
    }
}

对于 来说,JAVA方法可以映射到 中的任何或者对象方法。

虽然 和我们常用的java JNI有些类似,但是 存在着一些限制。

大部分情况下, 和 具有相同的映射类型,但是不支持

////数组作为函数参数值。

在使用或者的情况下, 不支持 NIO 或者基本类型的数组作为返回值。

如果要使用基础类型的包装类,则必须使用自定义的.

对象JAVA中的方法映射来说,该映射最终会创建一个对象。

讲完 和 之后,我们接下来讲解一下 。

代表的是中的PPER,它对应的值是一个。

之前我们提到了,可以实现JAVA中定义的方法名和 lib中的方法名不同,但是不能修改方法调用的状态或者过程。

而则更进一步,允许您任意重新配置函数调用java native,包括更改方法名称以及重新排序、添加或删除参数。

下面举个例子:

   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;
       }
   }

看上面的调用例子,感觉有点像是反射调用,我们在中实现了方法,根据给定的JAVA代码中的去查找具体的 lib,然后获取到lib中的,最后调用的方法实现方法的最终调用。

在这个过程中,我们可以修改方传入的参数,或者做任何我们想做的事情。

还有一种情况是c语言中的内联函数或者预处理宏java native java高级用法之:在JNA中将本地方法映射到JAVA代码中,如下所示:

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

上面的代码中定义了一个(x)宏,它实际上等于(x * 1024),这种情况就可以使用,将使用具体的来替换:

   // 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方法和方法映射肯定会出现一些问题,如果映射方法不对或者参数不匹配的话,很有可能出现 ,并且可能会导致VM崩溃。

通过调用.(true),可以将VM崩溃转换成为对应的JAVA异常,当然,并不是所有的平台都支持,如果平台不支持java native,那么.()会返回false。

如果要使用,还要同时使用 jsig ,以防止信号和JVM的信号冲突。.so一般存放在JRE的lib目录下,{java.home}/lib/java.home/lib/{os.arch}/.so, 可以通过将环境变量设置为 (或者)来使用。

性能考虑

上面我们提到了JNA的两种方式,分别是 和 。相较而言, 的效率更高,因为 调用方法更加高效。

但是上面我们也提到了 在使用上有一些限制,所以我们在使用的时候需要进行权衡。

另外,我们需要避免使用基础类型的封装类,因为对于方法来说,只有基础类型的匹配,如果要使用封装类,则必须使用Type ,从而造成性能损失。

总结

JNA是调用方法的利器,如果数量掌握的话,肯定是如虎添翼。

本文已收录于

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

公告:
1. 本站所有资源来源于用户上传和网络,如有侵权请联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系站长处理!
6. 本站不售卖代码,资源标价只是站长收集整理的辛苦费!如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。
7. 站长QQ号码 2205675299

资源库 - 资源分享下载网 » java native java高级用法之:在JNA中将本地方法映射到JAVA代码中

常见问题FAQ

关于资源售价和售后服务的说明?
本站所有资源的标价均为本站收集资源的辛苦费,不代表资源本身的价值。软件是高智慧高价值的商品,不可能是白菜价。本站资源标价只是赞助费用,收取的赞助费仅用来维持本站的日常运营!毕竟收集整理资料需要投入云计算资源和站长大量的精力。
代码有没有售后服务和技术支持?
由于代码的运行具有不可预见性,本站不保证代码完整可运行,不提供技术支持和售后服务。 本站原创代码都是站长自己开发的,可以有偿提供技术支持服务。 网站里标明【亲测】的代码都是站长亲测过的,其他的代码由于精力有限,没有一一测试,不能保证代码就一定能够使用,更没有技术支持服务,下载前请自行斟酌。
有没有搭建服务?
由于搭建服务比较费时费力,所以本站除了原创代码外均不提供搭建服务。本站分享代码纯属兴趣爱好,不以盈利为目的,请勿咨询有没有搭建服务,谢谢理解。
链接地址失效了怎么办?
请带上资源链接地址联系客服,工作时间内我们看到后将第一时间回复。
关于解压密码
本站资源一般都没有加密,如果发现需要解压密码的,那么就输入 hao.35dc.com 试试。

发表评论

资源库,由老程序员细心甄别、精心筛选,只为提供优质的源码资源

关于我们 联系我们