JNA调用C++动态库

   1、Java调用本地C/C++动态库的方法
   大概主要有两种JNI(Java Native Interface)和JNA(Java Native Access),最后介绍一种大招。本文没有代码,只有引用人的文章,demo人家都已经写的很清楚了,我就是总结下以备自己查看。
   之后说下名称粉碎(name mangling)和性能损失。

    2、 JNI(Java Native Interface)
   JNI是java本地化的原始方法,是java与本地语言之间调用的桥梁。注意是之间,也就是说除了Java调用本地语言动态库,本地语言(不仅限于C、C++,还有诸如Delphi、VB等)同样也可以调用Java。
   
   其实现步骤大致分四步:
I. 编写java部分的接口代码,核心是声明native的方法,静态或实例级别均可。通过System.loadlibrary()指定需要调用的动态库名称。
II. 生成二进制文件.class,并根据.class用javah生成对应的.h头文件。
III. 编写本地代码,生成动态库。将动态库放至path变量的路径下,以供查找。
IV. java完成调用。

      这里说明的是javah针对的是二进制文件.class而不是源代码文件.java,运行javah时要在最顶层包的上一级目录,输入时要连包名一并输入,程序会自动完成包和class的解析。

    可供参考的文章:
            使用 Java Native Interface 的最佳实践(JNI)
            JNI相关参数传递
            数组
            调用运行时异常
            找不到jni.h的解决办法(fatal error C1083: Cannot open include file: 'jni.h':)

    关于一些常见的异常,尤其是C++库用mingw和cygwin的g++编译出来,可能会出现 java.lang.UnsatisfiedLinkError: XXXclass.XXXmethod()这个错误,VC则不会出现这个问题。这是由于编译时的一个奇怪的名称粉碎现象导致的,g++会在方法名前添加“@”符号,导致java调用失败,解决方法:
    生成不带@的函数声明
 :
    gcc -Wl,--kill-at -shared -o jnihello.dll Native.c

    
关于找不到jni.h的问题,他们在jdk的include目录下,包括jni.h、 win32\jni_md.h 、win32\jawt_md.h
    将这三个问文件放在   Visual Studio.net的安装目录下的\Vc xxx \include  下,
    mingw放在安装目录下的include目录中就可以,反正跟stdlib.h这样常用的库在一起就没问题了。

  3、JNA(Java Native Access) 
Sun官方的java本地访问项目(http://jna.java.net/),是一个库,用它可以大大简化java调用本地库的过程。这个东西有点像windows的loadlibrary和linux下的dlopen,都是动态装在库,可以在运行时根据需要装在符合接口的库。

    所以,根据描述,使用方法如下:
I.编写符合函数原型的接口(interface),并根据调用方式选择是扩展StdCallLibrary接口(stdcall)还是Library接口(其他方式)。
II.编写动态库,并放至path下。C++请使用  extern   "C"    __declspec( dllexport ) 作为导出函数前缀,以免编译器的 名称粉碎导致java调用不能。 *
III. 通过java的jna库的Native.loadlibrary()方法装载动态库。

   可供参考的文章: 
           JNA介绍
           还是JNA的介绍和Demo
           开源项目JNA-中文翻译版

    比JNI简单一些,效率损失根据实际情况也可以忽略.
     多说一句,这样编出来的C++动态库也可以在c#中被顺利调用。C#通过[DllImport]特性调用C++库时,需按照第 II 条规则编写代码。

     4、跨语言调用大招
你还想要大招?告诉你一个可别打我,就是创建子进程,然后对接子进程输出流,入参通过创建进程时的附加参数传入,返回结果自然就是本应该在命令行上出现的字符串了。
    其实就是编了个可执行的命令行,然后重定向了流,用途广泛。

     5、名称粉碎(Name Mangling)
    叫名字粉碎、名字改编也一样,主要是面向对象语言对应重载的机制。
    如果用记事本打开C++的导入库文件.o/.lib,以字符而非二进制方式查看,就可以找到我们的导出函数的名称,也可以发现其粉碎规则,名称粉碎对于不同的编译器方式不同,会干扰跨语言调用。

    可以参考的文章:
          Visual C++名字修饰
          Name mangling

        6、性能损失
      最后,java损失跨平台性调用本地库换来了功能的强大,但是性能损失多少,以及在java和c++上都能做的事情是交给谁做,频繁调用本地方法好不好,都是之后有时间需要测试的。
      [补充于2012年8月]
      最近又回来做一些C#调用C++的项目,其实,对于直接调用或者起子进程再对接流的方法,效率几乎是没有太大差别的,关于这个,想一想动态库的原理就可以明白。所以在不要求绝对效率和性能的情况下,不比太过在意,只需要选择合适的方案即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值