Java调用本地C/C++动态库拾遗 JNI/JNA与名称粉碎

转载 2013年12月03日 22:44:35
1、Java调用本地C/C++动态库的方法
  大概主要有两种JNI(Java Native Interface)和JNA(Java NativeAccess),最后介绍一种大招。本文没有代码,只有引用人的文章,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.dllNative.c

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

  3、JNA(Java NativeAccess) 
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++名字修饰
       Namemangling

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

转载自:http://blog.sina.com.cn/s/blog_3f2c72ea01011kvx.html

相关文章推荐

JNA java调用c/c++代码

最近在搞一个小程序,需要用java调用DLL。用到的技术是JNA。 具体的内容在网上一搜都有,但是很多帖子内容都差不多,而且都有些问题,也不知道是不是版本的问题,反正代码拿来一copy各种问题,倒腾...

Java 调用 C/C++ 之 JNA 系列实战篇 —— 输出char * (六)

一、 工作环境             1. windows (64位), JDK (64位),dll文件 (64位)         2. Linux (64位),      JDK (...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

JAVA 通过 JNA 调用 C程序 dll 函数传入中文参数问题

解决JAVA 通过 JNA 调用 C程序 dll 函数传入中文参数问题

Java调用C语言动态库(JNA方式):回调函数、结构体数组传参、结构体数组返回

一、开发环境 系统、开发环境:win7、eclipse 32位、jdk 32位、jre 32位 由于这里使用的dll文件是32位的,而我本身的环境是64位的,包括eclipse、jdk、jre都是...
  • ggmove
  • ggmove
  • 2013年12月17日 16:13
  • 5872

Jna调用动态链接库

最近由于工作需要,在和其它系统交互的问题上不仅仅是WebService的交互,还需要利用Java调用其它语言编写的动态链接库,例如编译好的dll文件.好,简单看一下这个问题的来源。          ...

jna java 调用c动态库

  • 2010年08月23日 19:40
  • 182KB
  • 下载

Java调用C/C++实现的DLL动态库——JNI

Java调用C/C++实现的DLL动态库——JNI 由于项目的需要,最近研究了java 调用DLL的方法,将如何调用的写于此,便于日后查阅: 采用的方法是JNI:Java Native Int...
  • H002399
  • H002399
  • 2015年08月30日 14:44
  • 433

JAVA使用JNI调用C/C++动态库

转自:http://blog.sina.com.cn/s/blog_4087649401012due.html 在实际使用中,我们经常会在JAVA和C/C++之间进行交互,比较通用的方法目前...

Java调用C/C++实现的DLL动态库——JNI

转自:http://www.cnblogs.com/xiehy/p/3365682.html 由于项目的需要,最近研究了java 调用DLL的方法,将如何调用的写于此,便于日后查阅: 采用的方法是...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java调用本地C/C++动态库拾遗 JNI/JNA与名称粉碎
举报原因:
原因补充:

(最多只允许输入30个字)