zoukankan      html  css  js  c++  java
  • jna编程学习

    1. 什么是JNA

    JNI:是java和其他语言相互调用的机制,c 或者 c++写的库,java想使用,需要调用dll库,这就需要使用JNI或者JNA去封装库提供的API。
    JNA:是JNI的更高封装,JNA使用很方便,JNI使用就相对麻烦,需要把dll中的每个API封装一次,封装的函数去调用dll中的API。JNA则直接声明一下dll中的API,对应工作JNA都做了,我理解就是JNI的封装本来是自己写,但是JNA都帮你做了,所以使用起来JNA方便。



    2. 为什么学习JNA

    工作中需要用java调用c的dll完成一些工作。
    官网:https://github.com/java-native-access/jna 可以去这里看依赖或下载jar包



    3. 使用JNI编程

    缺点:比较繁琐
    调用流程:

    参考:https://blog.csdn.net/u014132659/article/details/56489375
    https://www.cnblogs.com/lanxuezaipiao/p/3635556.html



    4. 使用JNA编程

    JNA是JNI更高的封装。
    JNA(Java Native Access)是一个开源的Java框架,是Sun公司推出的一种调用本地方法的技术,是建立在经典的JNI基础之上的一个框架。之所以说它是JNI的替代者,是因为JNA大大简化了调用本地方法的过程,使用很方便,基本上不需要脱离Java环境就可以完成。
    调用流程:




    5. JNA技术原理

    JNA使用一个小型的JNI库插桩程序来动态调用本地代码。开发者使用Java接口描述目标本地库的功能和结构,这使得它很容易利用本机平台的功能,而不会产生多平台配置和生成JNI代码的高开销。这样的性能、准确性和易用性显然受到很大的重视。
    此外,JNA包括一个已与许多本地函数映射的平台库,以及一组简化本地访问的公用接口。
    注意:

    • JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。
    • 原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。
    • JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射,你不再需要编写C动态链接库。
    • 也许这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。但总体影响不大,因为JNA也避免了JNI的一些平台配置的开销。



    6. JNA简单使用-----调用C的printf函数打印出“HelloWorld”

    步骤1 需要定义一个接口,继承自Library 或StdCallLibrary

    默认的是继承Library ,如果动态链接库里的函数是以stdcall方式输出的,那么就继承StdCallLibrary。
    接口中只需要定义你要用到的函数或者公共变量。
    注意参数和返回值的类型,应该和链接库中的函数类型保持一致。

    interface CLibrary extends Library {
    	CLibrary INSTANCE = (CLibrary)Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),CLibrary.class);
    	
    	/**  
    	 * @return void
    	 * @Author 91李寻欢
    	 * @Description 打印函数
    	 * @Date 2021/5/11 9:24 
    	 * @Param [format, args] 
    	 **/
    	void printf(String format, Object... args);
    }
    

    步骤2 接口内部需要一个公共静态常量:INSTANCE,通过这个常量,就可以获得这个接口的实例,从而使用接口的方法,也就是调用外部dll/so的函数

    该常量通过Native.loadLibrary()这个API函数获得。
    该API函数有2个参数:

    参数1:
          是动态链接库dll/so的名称,但不带.dll或.so这样的后缀,这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。
          搜索动态链接库路径的顺序是:先从当前类的当前文件夹找,如果没有找到,再在工程当前文件夹下面找win32/win64文件夹,找到后搜索对应的dll文件,如果 找不到再到WINDOWS下面去搜索,再找不到就会抛异常了。比如下例中printf函数在Windows平台下所在的dll库名称是msvcrt,而在 其它平台如Linux下的so库名称是c。
    
    参数2:
          本接口的Class类型。JNA通过这个Class类型,根据指定的.dll/.so文件,动态创建接口的实例。该实例由JNA通过反射自动生成。
    
    public static void main(String[] args) {
    	CLibrary.INSTANCE.printf("Hello, World
    ");
    }
    

    步骤3 调用链接库中的函数

    定义好接口后,就可以使用接口中的函数即相应dll/so中的函数了,调用方法就是通过接口中的实例进行调用。

    public static void main(String[] args) {
    	CLibrary.INSTANCE.printf("Hello, World
    ");
    	for (int i=0;i < args.length;i++) {
    		CLibrary.INSTANCE.printf("Argument %d: %s
    ", i, args[i]);
    	}
    }
    


    7. JNA技术难点

    有过跨语言、跨平台开发的程序员都知道,跨平台、语言调用的难点,就是不同语言之间数据类型不一致造成的问题。绝大部分跨平台调用的失败,都是这个问题造成的。关于这一点,不论何种语言,何种技术方案,都无法解决这个问题。JNA也不例外。

    上面说到接口中使用的函数必须与链接库中的函数原型保持一致,这是JNA甚至所有跨平台调用的难点,因为C/C++的类型与Java的类型是不一样的,你必须转换类型让它们保持一致,比如printf函数在C中的原型为:

    void printf(const char *format, [argument]);
    

    你不可能在Java中也这么写,Java中是没有char *指针类型的,因此const char *转到Java下就是String类型了。
    NA官方给出的默认类型映射表如下:还有很多其它的类型映射,需要的请到JNA官网查看。




    8. JNA调用C详细讲解

    https://blog.csdn.net/ggmove/article/details/17377117

  • 相关阅读:
    Spring中使用RedisTemplate操作Redis(spring-data-redis)
    Cron表达式
    自己搭建v,p,n过程
    CentOS 7安装与配置jdk-8u162
    .net自动生成版本号
    关于webapi 返回的类型的笔记
    多个系统间交互-灰度发布-一些笔记
    Unity的使用
    mysql中查询"_"这种特殊字符
    关于MVC中DropDownListFor的一个bug
  • 原文地址:https://www.cnblogs.com/itlihao/p/14746905.html
Copyright © 2011-2022 走看看