自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java調(diào)用C/C++編寫(xiě)的第三方dll動(dòng)態(tài)鏈接庫(kù)

開(kāi)發(fā) 后端
這里主要用的方法是JNI。在網(wǎng)上查資料時(shí)看到很多人說(shuō)用JNI非常的復(fù)雜,不僅要看很多的文檔,而且要非常熟悉C/C++編程??峙掠泻芏嗳嗽诳吹街T如此類(lèi)的評(píng)論時(shí)已經(jīng)決定繞道用其他方法了。本文將做詳細(xì)的介紹。

最近在用weka做一個(gè)數(shù)據(jù)挖掘相關(guān)的項(xiàng)目,不得不說(shuō),weka還是一個(gè)不錯(cuò)的開(kāi)放源代碼庫(kù),提供了很多最常用的分類(lèi)和聚類(lèi)算法。

在我的項(xiàng)目中要用到一個(gè)聚類(lèi)算法,Affinity Propagation(AP),由多倫多大學(xué)的Brendan J. Frey發(fā)表于2007年。相比其他的聚類(lèi)算法,AP算法的聚類(lèi)結(jié)果更加準(zhǔn)確。

在AP的官方網(wǎng)站公布了AP算法的動(dòng)態(tài)鏈接庫(kù),我的目標(biāo)就是實(shí)現(xiàn)在Java工程中調(diào)用這個(gè)動(dòng)態(tài)鏈接庫(kù)。

在網(wǎng)上查了資料,發(fā)現(xiàn),如果僅僅是想調(diào)用Windows的Native API還是比較省事的,這里我主要針對(duì)第三方dll的調(diào)用。

下面進(jìn)入正題。

這里主要用的方法是JNI。在網(wǎng)上查資料時(shí)看到很多人說(shuō)用JNI非常的復(fù)雜,不僅要看很多的文檔,而且要非常熟悉C/C++編程??峙掠泻芏嗳嗽诳吹街T如此類(lèi)的評(píng)論時(shí)已經(jīng)決定繞道用其他方法了。但是,假如你要實(shí)現(xiàn)的功能并不復(fù)雜(簡(jiǎn)單的參數(shù)傳遞,獲取返回值等等),我還是支持使用這個(gè)方法的。

Java Native Interface,簡(jiǎn)稱(chēng)JNI,是Java平臺(tái)的一部分,可用于讓Java和其他語(yǔ)言編寫(xiě)的代碼進(jìn)行交互。下面是從網(wǎng)上摘取的JNI工作示意圖。


圖1 JNI的工作模式

下面就舉具體的例子說(shuō)明一下使用步驟:

1) 編寫(xiě)一個(gè)類(lèi),聲明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.     }  

上面是APCluster.java文件,定義了一個(gè)APCluster類(lèi),其中有一個(gè)方法CallAPClusterDll(),需要傳遞三種不同類(lèi)型的參數(shù),并且返回一個(gè)整型數(shù)組。

注意,這里只需要聲明這個(gè)方法,并不需要實(shí)現(xiàn),具體實(shí)現(xiàn)就在APClusterDllMedium中。

APClusterDllMedium就像中介一樣,Java通過(guò)調(diào)用這個(gè)中介Dll中的CallAPClusterDll方法,間接調(diào)用真正的第三方Dll。

2)編譯生成.h文件

第一步:

javac APCluster.java 生成APCluster.class

第二步:

javah APCluster 生成APCluster.h頭文件,內(nèi)容如下:

  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這個(gè)頭文件的內(nèi)容是不能修改的,否則JNI會(huì)找不到相對(duì)應(yīng)的CallAPClusterDll()的實(shí)現(xiàn)。

3)創(chuàng)建C/C++工程,實(shí)現(xiàn)CallAPClusterDll()方法。

創(chuàng)建一個(gè)C/C++工程,工程名為APClusterDllMedium(其實(shí),生成的dll名為APClusterDllMedium即可),導(dǎo)入APCluster.h這個(gè)頭文件,并創(chuàng)建一個(gè)CPP文件,實(shí)現(xiàn).h文件中的方法。

 
圖2 新建工程結(jié)構(gòu)

由于我創(chuàng)建的工程是win32控制臺(tái)程序,所以最后默認(rèn)生成的是.exe文件,所以還要做一步工程屬性修改,讓它生成.dll后綴文件。

打開(kāi)Project Property ->General,做以下修改:

 
圖3 修改工程屬性

下面就是實(shí)現(xiàn) JNIEXPORT jintArray JNICALL Java_APCluster_CallAPClusterDll (JNIEnv *, jobject, jint, jdoubleArray, jboolean); 這個(gè)方法了。先貼代碼再慢慢解釋吧。

  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")))    //具體調(diào)用apcluster32方法  
  18.     {  
  19.         printf("GetProcAddress() failed: %d\n", GetLastError());   
  20.     }  
  21.     int        m_int = _arg_int;  //類(lèi)型轉(zhuǎn)換  
  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所在的目錄。

打開(kāi)Project Property -> C/C++ -> General -> Additional Include Directories添加相應(yīng)目錄:

 
圖4 添加JNI目錄

b)在APCluster.h文件中自動(dòng)生成的函數(shù),只標(biāo)識(shí)了函數(shù)參數(shù)類(lèi)型,為了引用這些參數(shù),自己起一個(gè)相應(yīng)的名字:

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

c)聲明函數(shù)指針,就是你要調(diào)用的第三方dll中函數(shù)的類(lèi)型。

d)LoadLibrary,導(dǎo)入真正的第三方Dll,并找到要調(diào)用的方法的函數(shù)地址。

把這個(gè)函數(shù)地址賦值給函數(shù)指針,接下來(lái)就可以通過(guò)這個(gè)函數(shù)指針調(diào)用真正的apcluster函數(shù)了!

e)類(lèi)型轉(zhuǎn)換:

讀讀jni.h文件就知道jdouble和double其實(shí)是一個(gè)東西,jboolean就是unsigned char類(lèi)型,jni.h中是這么聲明的:

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

但是數(shù)組類(lèi)型就沒(méi)有這么簡(jiǎn)單,獲取數(shù)組要使用類(lèi)型相對(duì)應(yīng)的env->GetTypeArrayElement(jTypeArray...)。

最后,要返回一個(gè)jint類(lèi)型的數(shù)組,就要新創(chuàng)建一個(gè)此類(lèi)型的數(shù)組,再為其賦值:

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

其中,_arg_int代表的是創(chuàng)建數(shù)組的長(zhǎng)度。

最后return result。

4)Build這個(gè)工程。

Build,生成相應(yīng)的APCluster.dll文件,將這個(gè)dll放到j(luò)ava工程目錄下。

 
圖5 將生成的dll放到j(luò)ava工程下

5)編寫(xiě)測(cè)試java程序,調(diào)用dll庫(kù)。

以下為測(cè)試程序,Test.java:

  1. public class Test    
  2. {  
  3.     public static void main(String[] args)   
  4.     {   
  5.         double     arg_doublearray[] = {0.10.20.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.     }  

到此,java調(diào)用第三方dll就基本完成了。

本文也主要是介紹大概的操作流程,至于具體應(yīng)該使用哪些API就只有去研究官方文檔了。

另外還有一些需要注意的問(wèn)題,比如64位的程序去調(diào)用32位的dll會(huì)報(bào)錯(cuò)啊等等...這些都是細(xì)節(jié)問(wèn)題了。

最后,個(gè)人認(rèn)為,自己動(dòng)手實(shí)踐還是很重要,網(wǎng)上都說(shuō)這個(gè)復(fù)雜那個(gè)難,但是至于難還是不難,還是要實(shí)踐了才知道...不能不去嘗試...

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

【編輯推薦】

  1. 深入理解JavaScript之強(qiáng)大的原型和原型鏈
  2. 制作完整的Java可執(zhí)行文件
  3. Apache Camel 2.9.0發(fā)布 Java規(guī)則引擎
  4. JActor 1.0發(fā)布 Actor模式的Java實(shí)現(xiàn)
  5. 深入Java虛擬機(jī)之內(nèi)存優(yōu)化
責(zé)任編輯:林師授 來(lái)源: 金玉姬的博客
相關(guān)推薦

2024-03-01 20:59:11

C#DLL開(kāi)發(fā)

2009-08-05 16:29:18

C#調(diào)用C++動(dòng)態(tài)鏈接

2011-05-18 17:15:45

2012-01-04 14:02:26

JsonCpp

2010-02-01 17:37:35

C++調(diào)用C鏈接庫(kù)

2019-07-30 11:35:54

AndroidRetrofit庫(kù)

2015-11-05 16:44:37

第三方登陸android源碼

2009-10-29 16:36:49

VB.NET .DLL

2013-04-07 15:13:21

CocoaPods第三方庫(kù)管理利器

2009-08-28 16:19:30

C#實(shí)現(xiàn)修改動(dòng)態(tài)鏈接庫(kù)

2014-07-22 10:56:45

Android Stu第三方類(lèi)庫(kù)

2023-08-02 10:10:00

C#C++

2009-08-05 16:49:42

C#中調(diào)用dll

2020-10-29 09:56:23

Linux靜態(tài)庫(kù)動(dòng)態(tài)庫(kù)

2022-06-06 07:50:55

PythonJSON

2011-07-25 14:14:49

iPhone SQLITE Pldatabase

2023-03-15 15:58:11

Python動(dòng)態(tài)庫(kù)C++

2017-12-11 15:53:56

2021-10-11 06:38:52

Go開(kāi)源庫(kù)語(yǔ)言

2014-07-23 08:55:42

iOSFMDB
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)