这里主要用的方法是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

来源: http://developer.51cto.com/art/201201/311363.htm

来自为知笔记(Wiz)

Java调用C/C++编写的第三方dll动态链接库(zz)相关推荐

  1. 转Java调用C/C++编写的第三方dll动态链接库(非native API)--- JNI

    http://www.cnblogs.com/AnnieKim/archive/2012/01/01/2309567.html 转载于:https://www.cnblogs.com/meetrice ...

  2. c调用python第三方库_用 Python ctypes 来调用 C/C++ 编写的第三方库

    看到一篇简洁的文章--如何用Python ctypes调用C++(ctypes调用C没这么多麻烦事),不敢独享... 如果需要用 Python 调用 C/C++ 编写的第三方库(这些第三方库很可能就是 ...

  3. java调用C或者C++动态库dll

    java调用C或者C++动态库dll,本文章使用的是IntelliJ IDEA Community Edition 2021.2.3版本测试的 1.新建项目 linjie.demo,添加类HelloL ...

  4. java调用百望税控NISEC_SKSC.dll发送xml报文

    1.第一个问题:Java调用dll文件 JNative方式调用dll JNative是一种能够使Java语言使调用DLL的一种技术,对JNI进行了封装,可能有些读者会有这样一个问题,JNative对J ...

  5. java dll 调用方法_关于Java调用dll的方法 | 学步园

    Java语言本身具有跨平台性,如果通过Java调用DLL的技术方便易用,使用Java开发前台界面可以更快速,也能带来跨平台性. Java调用C/C   写好的DLL库时,由于基本数据类型不同.使用字节 ...

  6. android调用 qt so文件路径,Android Java调用Qt写的so库

    有时候,我们反编译apk得到一个so库,如果直接使用这个so库的话,必须使用原来so库同样的package名字,才能用.这样人家反编译你的apk,就知道你侵犯了人家的版权.为了达到混淆的目的,我们可以 ...

  7. (JNI/JNA)java 调用c/c++ 动态链接库 全套操作+踩坑集锦

    第一篇文章终于写完-跨行三年,一直都是看别人的文章-今天咱终于自己写了一篇,自己总结的,希望能给你一点点帮助,如有错误,希望指出,立马改正. 0 前言 Java代码是跨平台的,其与硬件环境彻底&quo ...

  8. 明华读卡器 java_Java调用明华RF读写器DLL文件过程解析

    这篇文章主要介绍了Java调用明华RF读写器DLL文件过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 首先jdk必须得是32位的,IDE也必 ...

  9. Java调用第三方dll

    刚接触Java几天,项目需要,使用Java调用can卡的dll,发现网上的帖子有很多不明确的地方,特此写之. 首先安装开发环境,考虑到兼容性,安装的JDK和eclipse都是32位的,正常安装结束后, ...

最新文章

  1. Hive表与hdfs文件关联
  2. pyhanlp 分词与词性标注
  3. Geoffrey Hinton那篇备受关注的Capsule论文
  4. VS 之 InstallShield Limited Edition for Visual Studio 2015 图文教程
  5. day01『NLP打卡营』实践课1:词向量应用演示
  6. dubbo实现原理之SPI简介
  7. 5g上行速率怎么提升_揭秘联发科5G独家技术,攻克上行覆盖和终端功耗两大技术难题...
  8. Java面向对象16种原则
  9. RoterOS负载均衡教程
  10. 数据结构与算法之 树
  11. python入门-零基础 Python 入门
  12. CSS3图片动画展示----心跳
  13. 电机正反转的远程计算机控制,plc控制电机正反转原理图
  14. web开发工程师面试题,CSS盒子模型居中方法
  15. r730xd外置光驱安装linux,PowerEdge r730xd 安装centos 6.7
  16. 香蕉派 BPI-M2 Zero 四核开源单板计算机 全志 H2+/H3 芯片 高端设计
  17. Spring Boot系列六 Spring boot集成mybatis、分页插件pagehelper
  18. Python基础-*args和**kwargs魔法变量
  19. WPF快速入门2—布局WrapPanel,DockPanel,StackPanel,Canvas
  20. 大数据告诉你中老年人上网爱干什么

热门文章

  1. php用命令查mysql_phpMySQL命令大全总结
  2. linux cuda 如何编译器,linux – Cuda编译器不使用GCC 4.5
  3. 动力电池检测电压c语言编程,动力电池PACK EOL测试系统
  4. 情人节 html5,情人节H5案例 | 2019第一波情人节营销已上线
  5. python统计小说人物_Python数据分析之基情的择天记
  6. slf4j导入那个依赖_学习SPRINGBOOT结合日志门面SLF4J和日志实现LOGBACK的混合使用
  7. linux配置文件怎么把某行后几个字符替换_vim(Linux运维)
  8. 【基础知识】如何快速转发CSDN博客
  9. nodejs 根据坐标 标记图片上的姓名列
  10. 计算机控制里ddc什么缩略语,空调自动化术语和缩略语.doc