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

Java通过JNI调用Eclipse、MinGW编译C++出来的dll

  • 2014年02月01日 15:01
  • 646KB
  • 下载

关于MinGW下.dll.a文件的作用

 .dll.a文件的最初用意其实是MinGW下的DLL文件的imp-lib,即与VC下DLL文件附带了一个引入库.lib类似。在VC下编程,当要使用DLL文件时,在开发时必须要有.lib文件才能链接通...
  • chaosllgao
  • chaosllgao
  • 2010年03月14日 14:45
  • 7976

整理MINGW编译dll使用JNI被java调用的几种方式

 第一种方式,在msys中直接编译各个源文件,不管是c或者c++文件,都能生产被JNI调用的dll库 JNI-MINGW-DLL Posted August 10th, 2008 by fhacken...
  • zjuylok
  • zjuylok
  • 2009年05月05日 21:13
  • 2847

MinGW-GCC 如何编译JNI程序进阶

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Jav...
  • u010605082
  • u010605082
  • 2016年03月18日 17:00
  • 1633

JNI引用C++dll若干问题总结-如何导出C++中的类成员函数

最近做项目使用JNI引用C++的dll,在此记录遇到的问题。1.如何导出C++中的类 大家都知道JNI只能导出全局函数,至少我搜索了好久都没看到过有导出类的,貌似不可以。当然如果可以就更好了。那么既...
  • birdflyto206
  • birdflyto206
  • 2016年09月14日 13:51
  • 730

Java学习之通过JNI调用C/C++编写的dll链接库(图文教程)

看了网上几个主要的教程,都会导致出现各种错误,对于初学者来说会造成一些困扰。在这里详细记录一下JNI调用过程。本案例的基本配置:Eclipse+VS2015,Win10  64位 (1)编写Java ...
  • whustyle
  • whustyle
  • 2015年10月14日 14:35
  • 2055

【转载整理】eclipse 开发c/c++、Java使用JNI调用C程序、生成64位dll动态链接库

eclipse 开发c/c++、Java使用JNI调用C程序、生成64位dll动态链接库
  • Jul_11th
  • Jul_11th
  • 2017年11月24日 09:32
  • 141

MinGW gcc 生成动态链接库 dll 的一些问题汇总

网络上关于用 MinGW gcc 生成动态链接库的文章很多。介绍的方法也都略有不同。这次我在一个项目上刚好需要用到,所以就花了点时间将网上介绍的各种方法都实验了一遍。另外,还根据自己的理解试验了些网上...
  • liyuanbhu
  • liyuanbhu
  • 2015年01月11日 17:25
  • 18176

MinGW gcc 生成动态链接库 dll 的一些问题汇总 (补充)

我曾经写过一个小短文,介绍MinGW gcc 生成动态链接库 dll 的一些问题。当时写的并不全面。最近又遇到写新的问题。这里记录一下,做个补充。 通常情况下,dll 中的函数如果采用 _std...
  • liyuanbhu
  • liyuanbhu
  • 2015年03月16日 22:21
  • 2847

JNA入门1

1、jna是什么 jna是java native access的简称,用他可以调用C、C++代码,特别是windows中强大的库文件(dll,在linux下是so文件),这样java就可以操控底层的...
  • tianlang519241
  • tianlang519241
  • 2017年04月07日 10:40
  • 205
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java调用本地C/C++动态库拾遗 JNI/JNA与名称粉碎
举报原因:
原因补充:

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