这里主要用的方法是JNI。在网上查资料时看到很多人说用JNI非常的复杂,不仅要看很多的文档,而且要非常熟悉C/C++编程。恐怕有很多人在看到诸如此类的评论时已经决定绕道用其他方法了。本文将做详细的介绍。

AD:51CTO网+ 首届中国APP创新评选大赛火热招募中……

最近在用weka做一个数据挖掘相关的项目,不得不说,weka还是一个不错的开放源代码库,提供了很多最常用的分类和聚类算法。

在我的项目中要用到一个聚类算法,Affinity Propagation(AP),由多伦多大学的Brendan J. Frey发表于2007年。相比其他的聚类算法,AP算法的聚类结果更加准确。

在AP的官方网站公布了AP算法的动态链接库,我的目标就是实现在Java工程中调用这个动态链接库。

在网上查了资料,发现,如果仅仅是想调用Windows的Native API还是比较省事的,这里我主要针对第三方dll的调用。

下面进入正题。

这里主要用的方法是JNI。在网上查资料时看到很多人说用JNI非常的复杂,不仅要看很多的文档,而且要非常熟悉C/C++编程。恐怕有很多人在看到诸如此类的评论时已经决定绕道用其他方法了。但是,假如你要实现的功能并不复杂(简单的参数传递,获取返回值等等),我还是支持使用这个方法的。

Java Native Interface,简称JNI,是Java平台的一部分,可用于让Java和其他语言编写的代码进行交互。下面是从网上摘取的JNI工作示意图。


图1 JNI的工作模式

下面就举具体的例子说明一下使用步骤:

1) 编写一个类,声明native方法

  1. public class APCluster {
  2. public native int[] CallAPClusterDll( int         arg_Int,
  3. double[]    arg_DoubleArray,
  4. boolean     arg_boolean);
  5. static
  6. {
  7. System.loadLibrary("APClusterDllMedium");
  8. }
  9. }

上面是APCluster.java文件,定义了一个APCluster类,其中有一个方法CallAPClusterDll(),需要传递三种不同类型的参数,并且返回一个整型数组。

注意,这里只需要声明这个方法,并不需要实现,具体实现就在APClusterDllMedium中。

APClusterDllMedium就像中介一样,Java通过调用这个中介Dll中的CallAPClusterDll方法,间接调用真正的第三方Dll。

2)编译生成.h文件

第一步:

javac APCluster.java 生成APCluster.class

第二步:

javah APCluster 生成APCluster.h头文件,内容如下:

  1. /* DO NOT EDIT THIS FILE - it is machine generated */
  2. #include <jni.h>
  3. /* Header for class APCluster */
  4. #ifndef _Included_APCluster
  5. #define _Included_APCluster
  6. #ifdef __cplusplus
  7. extern "C" {
  8. #endif10 /*
  9. * Class:     APCluster
  10. * Method:    CallAPClusterDll
  11. * Signature: (I[DZ)[I
  12. */
  13. JNIEXPORT jintArray JNICALL Java_APCluster_CallAPClusterDll
  14. (JNIEnv *, jobject, jint, jdoubleArray, jboolean);
  15. #ifdef __cplusplus
  16. }
  17. #endif21
  18. #endif

注意,APCluster.h这个头文件的内容是不能修改的,否则JNI会找不到相对应的CallAPClusterDll()的实现。

3)创建C/C++工程,实现CallAPClusterDll()方法。

创建一个C/C++工程,工程名为APClusterDllMedium(其实,生成的dll名为APClusterDllMedium即可),导入APCluster.h这个头文件,并创建一个CPP文件,实现.h文件中的方法。

 
图2 新建工程结构

由于我创建的工程是win32控制台程序,所以最后默认生成的是.exe文件,所以还要做一步工程属性修改,让它生成.dll后缀文件。

打开Project Property ->General,做以下修改:

 
图3 修改工程属性

下面就是实现 JNIEXPORT jintArray JNICALL Java_APCluster_CallAPClusterDll (JNIEnv *, jobject, jint, jdoubleArray, jboolean); 这个方法了。先贴代码再慢慢解释吧。

  1. #include "APCluster.h"
  2. #include <stdio.h>
  3. #include <windows.h>
  4. #ifdef __cplusplus
  5. extern "C" {
  6. #endif
  7. typedef int*  (__stdcall *APCLUSTER32)(double*, unsigned int, bool);
  8. JNIEXPORT jintArray JNICALL Java_APCluster_CallAPClusterDll
  9. (JNIEnv *env, jobject _obj, jint _arg_int, jdoubleArray _arg_doublearray, jboolean _arg_boolean)
  10. {
  11. HMODULE dlh = NULL;
  12. APCLUSTER32 apcluster32;
  13. if (!(dlh=LoadLibrary("apclusterwin.dll")))        //第三方DLL位置
  14. {
  15. printf("LoadLibrary() failed: %d\n", GetLastError());
  16. }
  17. if (!(apcluster32 = (APCLUSTER32)GetProcAddress(dlh, "apcluster32")))    //具体调用apcluster32方法
  18. {
  19. printf("GetProcAddress() failed: %d\n", GetLastError());
  20. }
  21. int        m_int = _arg_int;  //类型转换
  22. double*    m_doublearray = env->GetDoubleArrayElements(_arg_doublearray, NULL);
  23. bool       m_boolean = _arg_boolean;
  24. int* ret = (*apcluster32)(m_doublearray, m_int, m_boolean); /* actual function call */
  25. jintArray result = env->NewIntArray(_arg_int);
  26. env->SetIntArrayRegion(result, 0, _arg_int, (const jint*)ret);
  27. FreeLibrary(dlh); /* unload DLL and free memory */
  28. if(ret)
  29. {
  30. free(ret);
  31. }
  32. return result;
  33. }
  34. #ifdef __cplusplus
  35. }
  36. #endif

a)首先为了#include <jni.h>,必须添加JNI所在的目录。

打开Project Property -> C/C++ -> General -> Additional Include Directories添加相应目录:

 
图4 添加JNI目录

b)在APCluster.h文件中自动生成的函数,只标识了函数参数类型,为了引用这些参数,自己起一个相应的名字:

JNIEXPORT jintArray JNICALL Java_APCluster_CallAPClusterDll
(JNIEnv *env, jobject _obj, jint _arg_int, jdoubleArray _arg_doublearray, jboolean _arg_boolean) ......

c)声明函数指针,就是你要调用的第三方dll中函数的类型。

d)LoadLibrary,导入真正的第三方Dll,并找到要调用的方法的函数地址。

把这个函数地址赋值给函数指针,接下来就可以通过这个函数指针调用真正的apcluster函数了!

e)类型转换:

读读jni.h文件就知道jdouble和double其实是一个东西,jboolean就是unsigned char类型,jni.h中是这么声明的:

  1. typedef unsigned char    jboolean;
  2. typedef unsigned short   jchar;
  3. typedef short            jshort;
  4. typedef float            jfloat;
  5. typedef double           jdouble;

但是数组类型就没有这么简单,获取数组要使用类型相对应的env->GetTypeArrayElement(jTypeArray...)。

最后,要返回一个jint类型的数组,就要新创建一个此类型的数组,再为其赋值:

  1. jintArray result = env->NewIntArray(_arg_int);
  2. env->SetIntArrayRegion(result, 0, _arg_int, (const jint*)ret);

其中,_arg_int代表的是创建数组的长度。

最后return result。

4)Build这个工程。

Build,生成相应的APCluster.dll文件,将这个dll放到java工程目录下。

 
图5 将生成的dll放到java工程下

5)编写测试java程序,调用dll库。

以下为测试程序,Test.java:

  1. public class Test
  2. {
  3. public static void main(String[] args)
  4. {
  5. double     arg_doublearray[] = {0.1, 0.2, 0.3};
  6. int        arg_int = 3;
  7. boolean    arg_boolean = true;
  8. int[]  result = new APCluster().CallAPClusterDll(arg_int, arg_doublearray, arg_boolean);
  9. .....
  10. }
  11. }

到此,java调用第三方dll就基本完成了。

本文也主要是介绍大概的操作流程,至于具体应该使用哪些API就只有去研究官方文档了。

另外还有一些需要注意的问题,比如64位的程序去调用32位的dll会报错啊等等...这些都是细节问题了。

最后,个人认为,自己动手实践还是很重要,网上都说这个复杂那个难,但是至于难还是不难,还是要实践了才知道...不能不去尝试...

原文链接:http://www.cnblogs.com/AnnieKim/archive/2012/01/01/2309567.html

Java调用C/C++编写的第三方dll动态链接库(zz)的更多相关文章

  1. 关于在VB.NET中调用使用VC++编写的类库dll的一点笔记

    前言 结对作业要求一出来,我就立刻想到了把“计算核心”封装成dll,然后使用vb.net编写UI调用dll的思路.然而在实现过程中却遇到了很多的问题. 我在这个过程中是负责使用vb.net编写UI并调 ...

  2. 可供VC调用的QT编写的界面DLL方法

    一般直接编写的QT动态库是无法被Windows下的VC6.0等调用的. 如下步骤 第一步:必须要在QT界面库源码下包含qtwinmigrate的源码包和库,网上可下载到. 第二步:在QT的proc文件 ...

  3. Java调用明华RF读写器DLL文件的方法

    首先jdk必须得是32位的,IDE也必须是32位的(我用的idea,所以为了使用32位的,下载了2018年1月版本的). 明华RF读写器演示文件提供了一份名为mwrf32.dll的动态链接库文件 ja ...

  4. java调用C/C++写的dll(转)

    源:java调用C/C++写的dll Java语言本身具有跨平台性,如果通过Java调用DLL的技术方便易用,使用Java开发前台界面可以更快速,也能带来跨平台性. Java调用C/C++写好的DLL ...

  5. java调用dll-JNA

    介绍 给大家介绍一个最新的访问本机代码的 Java 框架 —JNA . JNA(Java Native Access) 框架是一个开源的 Java 框架,是 SUN 公司主导开发的,建立在经典的 JN ...

  6. Java调用外部程序常用算法和封装类

    一个项目不可能只使用一种编程语言来开发,也不可能由一个人开发,所以,Java程序员要学会和使用其他编程语言的程序员合作.那么,让我来发布一个工具类--Java外接程序扩展包,并将相应算法发布.Java ...

  7. Java调用第三方dll文件的使用方法 System.load()或System.loadLibrary()

    Java调用第三方dll文件的使用方法 public class OtherAdapter { static { //System.loadLibrary("Connector") ...

  8. [JNA系列]Java调用Delphi编写的Dll之JNA使用

    介绍 给大家介绍一个最新的访问本机代码的 Java 框架 —JNA . JNA(Java Native Access) 框架是一个开源的 Java 框架,是 SUN 公司主导开发的,建立在经典的 JN ...

  9. Eclipse、MinGW、JNI编写C++生成dll, Java端调用的完整示例(附java.lang.UnsatisfiedLinkError解决方法)

     Eclipse.MinGW.JNI编写C++生成dll, Java端调用的完整示例(附java.lang.UnsatisfiedLinkError解决方法) 问题背景:之前的JNI编程都是基于And ...

随机推荐

  1. .Net开源网络爬虫Abot介绍

    .Net中也有很多很多开源的爬虫工具,abot就是其中之一.Abot是一个开源的.net爬虫,速度快,易于使用和扩展.项目的地址是https://code.google.com/p/abot/ 对于爬 ...

  2. Linux Swap交换分区介绍总结

    Swap交换分区概念   什么是Linux swap space呢?我们先来看看下面两段关于Linux swap space的英文介绍资料: Linux divides its physical RA ...

  3. SQL Server(六)——索引、视图和SQL编程

    1.索引 添加索引,设计界面,在任何一列前右键--索引/键--点击进入添加某一列为索引 2.视图 视图就是我们查询出来的虚拟表 创建视图:create view 视图名 as SQL查询语句,分组,排 ...

  4. One to One 的数据库模型设计与NHibernate配置

    在数据库模型设计中,最基本的实体关系有三种:一对一.一对多.多对多.关于一对多和多对多使用的情况较多,之前也有过一些讨论,现在来说明一下在数据库中一对一的模型设计. 首先,关系数据库中使用外键来表示一 ...

  5. 0018 Java学习笔记-面向对象-类的基本要素

    类与对象 大街上一个个的人,就是一个个对象 类是对一群对象的抽象,比如人都有性别.年龄.姓名,都会吃饭.睡觉等.姓名性别可以抽象为变量,吃饭睡觉可以抽象为方法,像下面一样定义个类来形容人 public ...

  6. C语言基本类型之long long int

    大家都知道int在linux系统下默认是占4个字节,数值表示范围是:-2147483648~2147483647.即使是无符号unsigned int类型表示范围:0-4294967295,大约42亿 ...

  7. ICTCLAS中文分词库的使用

    ICTCLAS计算所中文分词(当前最好的汉语词法分析器)系统特点:准确度高(98.5%),性能优越(500KB/s分词速度),词性标注(POS tagging)且支持多种标注集,支持用户自定义词典,支 ...

  8. poj 2104 K-th Number(可持久线段树)

    K-th Number 持久化:http://www.cnblogs.com/tedzhao/archive/2008/11/12/1332112.html 结构:http://www.docin.c ...

  9. aircack-ng抓握手包

    1.关闭影响进程 airmon-ng check kill 将要进入监听模式的无线网卡断开它已连接的AP 2.查看无线网卡的名字 ifconfig ,例如 wlan0 3.进入监听模式: airmon ...

  10. Neutron分析(5)—— neutron-l3-agent中的iptables

    一.iptables简介 1.iptables数据包处理流程 以本机为目的的包,由上至下,走左边的路 本机产生的包,从local process开始走左边的路 本机转发的包,由上至下走右边的路 简化流 ...