• JNA


    JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架。使用JNI调用共享类库 (.dll/.so文件)是非常麻烦的事情,既需要编写java代码,又要编写C语言的代理方法,这其中需要很多数据类型的转换,是让人非常头痛。JNA 框架就是为了解决这些问题和繁琐的事情而开发的,它提供一组Java工具类用于在运行期动态访问系统本地共享类库而不需要编写任何Native/JNI代 码。开发人员只要在一个java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射,大大降低了Java调用本体共享库的开发难度。JNA与.NET平台上的P/Invoke机制一样简单和方便。

          你只需要下载一个jar包,就可以使用JNA的强大功能方便地调用动态链接库中的C函数。下载地址是:https://github.com/twall/jna

          JNA调用本地的库函数

        假设有一个动态链接库: CnblogsJna.dll。里面有这样一个函数:

    void sayHello(char * name){
        printf("C Code Start...
    ");
        printf("Hello! Mr %s.
    ",name);
        printf("C Code End.
    ");
    }

          此函数接收一个代表姓名的字符指针,然后在控制台上输出几句字符串。

          为了调用这个函数,使用JNA,我们需要编写下面的JAVA代码:

          1、接口ICnblogsJna.java

    复制代码
    import com.sun.jna.Library;
    import com.sun.jna.Native;
    
    /**
     * @author BCH)王国成
     */
    public interface ICnblogsJna extends Library {
        // 接口实例
        ICnblogsJna INSTANCE = (ICnblogsJna) Native.loadLibrary("CnblogsJna",ICnblogsJna.class);
    
        // 与C代码映射的函数
        public void sayHello(String name);
    }
    复制代码

          注意:接口需要继承制JNA的Library接口;

                 接口内部需要一个公共静态常量INSTANCE, 通过这个常量,就可以获得这个接口的实例,从而使用接口的方法。也就是调用动态链接库CnblogsJna.dll中的sayHello函数了。
                如 果使用JNI,你需要使用System.loadLibrary方法,来加载我们专为JNI编写的动态链接库,这个动态链接库实际上是我们真正需要的动态 链接库的代理。使用JNA是,需要用JNA类库的Native类的loadLibrary函数,是直接把我们需要的动态链接库载入进来。使用JNA,我们 不需要编写作为代理的动态链接库,不需要编写一行原生代码。
                Native类的loadLibrary方法有两个参数:第 一个参数是.dll或者.so文件的名字,但不带后缀名。这符合JNI的规范,因为带了后缀名就不可以跨操作系统平台了。第二个参数是本接口的Class 类型,JNA通过这个Class类型,根据指定的dll/.so文件,动态创建接口的实例。

          2、调用动态链接库文件中函数的Java方法():

    复制代码
    /**
     * @author BCH)王国成
     */
    public class CnblogsJna {
        /**
         * 入口函数
         * @param args
         */
        public static void main(String[] args) {
            // 调用动态链库中的sayHello函数
            ICnblogsJna.INSTANCE.sayHello("Wanggc/王国成");
        }
    }
    复制代码

          方法很简单,就像调用Java自己的函数一样。执行输出结果如下:

         

          和原生代码的类型映射

          跨平台,跨语言调用的难点,就是不同语言之间数据类型不一致造成的,JNA也不例外,要想跨平台调用,数据类型转换是个无法回避的问题。JNA提供了Java和原生代码的类型映射。

          Java和C数据类型的对应表如下:

    Java

    C

    原生表

     boolean

     int

     32位整数 (可定制)

     byte

     char 

     8位整数

     char

     wchar_t

     平台依赖

     short

     short

     16位整数

     int

     int

     32位整数

     long

    long long, __int64

     64位整数

     float

     float

     32位浮点数

     double

     double

     64位浮点数

     Buffer/Pointer

     pointer

     平台依赖(32或 64位指针)

     <T>[] (基本类型的数组)

     pointer/array

    32或 64位指针(参数/返回值)

    邻接内存(结构体成员)

     String

     char*

    /0结束的数组 (native encoding or jna.encoding)

     WString

     wchar_t*

     /0结束的数组(unicode)

     String[]

     char**

     /0结束的数组的数组

     WString[]

     wchar_t**

     /0结束的宽字符数组的数组

     Structure

     struct*/struct

    指向结构体的指针 (参数或返回值) (或者明确指定是结构体指针)
    结构体(结构体的成员) (或者明确指定是结构体)

     Union

    union 

     等同于结构体

     Structure[]

     struct[]

     结构体的数组,邻接内存

     Callback

     <T> (*fp)()

     Java函数指针或原生函数指针

     NativeMapped

     varies

     依赖于定义

     NativeLong

     long

     平台依赖(32或64位整数)

     PointerType

     pointer

     和 Pointer相同

          由于跨平台和跨语言尤其自身无法克服的确定,所以尽量少跨平台、跨语言传递数据。如果必须这样做,也尽量使用简单的数据类型。如果有复杂的数据类型需要在 Java和原生函数中传递,那么我们就必须在Java中模拟这种复杂的原生类型。这将大大增加实现的难度,甚至无法实现。如果在Java和原生函数间存在 大量的数据传递,一方面,会损失程序的性能;另一方面会造成内存碎片,Java调用原生函数时,会把数据固定在内存中,这样原生函数才可以访问这些 Java数据。这些数据,JVM的GC不能管理,就会造成内存碎片。

    作者:孤旅者
  • 相关阅读:
    pgloader-pg迁移神器
    PostgreSQL备份工具-pg_probackup
    5、pgpool-II高可用性(一)数据库的高可用性
    4、pgpool-II 流复制模式
    3、pgpool-II 内置复制模式
    pgpool-II 的配置
    pgpool-II安装
    PG时间相减
    PostgreSQL 流复制解惑
    PostgreSQL改造非分区表为分区表
  • 原文地址:https://www.cnblogs.com/rexienk/p/5755475.html
Copyright © 2020-2023  润新知