使用JNI進行Java與C/C++語言混合編程----在Java中調用C/C++生成的DLL動態連接庫html
JNI是Java Native Interface的英文縮寫,
中文翻譯爲本地調用, 自從Java 1.1開始就成爲了Java標準的一部分.
Java調用C/C++大概有這樣幾個步驟java
首先建立一個java工程,測試一下能不能調用openCV代碼:linux
public class hello { //不少教程會叫咱們聲明成static,可是我用的時候報錯了,因此我仍是 //不聲明成static了 public native void sayHello(String path); public static void main(String[] args) { // TODO Auto-generated method stub hello h=new hello(); //有時候會報錯說cannot load xxx.dll //只須要將生成的xxx.dll放到這 //條語句輸出的路徑下便可 System.out.println(System.getProperty("java.library.path")); //這裏調用的是java本地庫,TestAgain不加.dll。 //怎樣生成.dll後面會介紹 System.loadLibrary("TestAgain"); h.sayHello("D:/images/5.jpg"); }
}ios
因爲我用的是myeclipse編寫和編譯的Java程序,c++
只須要配置一下就能夠用myeclipse生成xxx.h文件,web
在myclipse->run->External Tools->External Tools configurations編程
通常須要選中一個工程才能run,而後就能夠生成xxx.h頭文件了
working Directory:${project_loc}
arguments:-v -classpath "${project_loc}/src" -d "${project_loc}/jni"
${java_type_name}segmentfault
製做.h文件還有一個更簡單的辦法,那就是直接cmd到當前工程的src目錄下,而後javah xxx(包名).xxx(類名),而後就能夠了,舉例假設包名爲com.action,類名爲upLoad,並且src目錄下
則應該是javah com.action.upLoad便可windows
這裏我也有些地方沒搞懂,由於我本身作這個項目的時候,用過jdk 1.6 1.7 1.8,最後使用的jdk1.6+tomcat6.0開發的,可是當我在location 中寫入jdk1.6 的bin/javah.exe,編譯個人javaweb工程時出現以下錯誤:數組
���������� com.servlet.HandleImg δ�ҵ� com.servlet.HandleImg �����ļ� javadoc: ���� - �Ҳ����� com.servlet.HandleImg�� [ Search Path: D:\jdk\jdk\jre\lib\resources.jar;D:\jdk\jdk\jre\lib\rt.jar;D:\jdk\jdk\jre\lib\sunrsasign.jar;D:\jdk\jdk\jre\lib\jsse.jar;D:\jdk\jdk\jre\lib\jce.jar;D:\jdk\jdk\jre\lib\charsets.jar;D:\jdk\jdk\jre\lib\modules\jdk.boot.jar;D:\jdk\jdk\jre\classes\D:\MyEclipseProfessional2014\workspace\HandleImage/src ] Error: δ����������ָ���κ��ࡣ�볢��ʹ�� -help��
所以我用的是我jdk1.7中bin/javah.exe生成的xxx.h頭文件,實在不行就只能下載兩個jdk了,知識水平有限,望有人能解決這個問題。
無論怎麼說,最終頭文件是生成了,xxx.h文件在當前工程jni文件夾下,以下圖:
打開後
而後就能夠開始寫c++代碼了
file->new ->project 選擇visual C++ 和win32 Console Application而後ok
個人操做系統和myeclipse都是64位的,所以生成32位的dll,在myeclipse中調用,會出現錯誤,這裏就須要配一下
而後就是配置opencv環境,我用的是opencv2.4.4,具體的配置過程,去百度opencv2.4.4配置教程,此次是在debug|x64下添加propertySheet了,
繼續添加兩個路徑:C:Program FilesJavajdk1.7.0_80include和C:Program FilesJavajdk1.7.0_80includewin32,目的是爲了引入三個頭文件jni.h和jni_md.h還有jawt_md.h
再就是右鍵工程 ->open folder in file explore 將上面生成的xxx.h文件copy到該文件夾下:
而後HeaderFile裏面也放一份
第二種引入改頭文件的方法是直接新建一個頭文件Test.h(名字能夠隨意取),而後將myEclipse中生成的頭文件的內容所有複製到Test.h中,而後在引用的時候將#include "com_Test_hello.h"改成#include "Test.h"便可
而後在source Files中新建TestAgain.cpp,代碼以下,
#include "com_Test_hello.h" #include <iostream> #include <opencv2\highgui\highgui.hpp> #include <opencv2\core\core.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <windows.h> using namespace std; using namespace cv; JNIEXPORT void JNICALL Java_com_Test_hello_sayHello (JNIEnv *env, jobject obj,jstring string){ const char* str = env->GetStringUTFChars(string, 0); char cap[128]; strcpy(cap, str); env->ReleaseStringUTFChars(string, 0); int len=strlen(cap); Mat imag, result; imag = imread(str,0); //將讀入的彩色圖像直接以灰度圖像讀入 //namedWindow("原圖", 1); // imshow("原圖", imag); result = imag.clone(); //進行二值化處理,選擇30,200.0爲閾值 threshold(imag, result, 30, 200.0, CV_THRESH_BINARY); //namedWindow("二值化圖像"); // imshow("二值化圖像", result); imwrite(str,result); printf("圖像二值化成功!"); }
而後就能夠build->build solution
如何使用Debug生成的解決方案的話,上面的那些環境就應該是在Debug下屬性表裏面添加,並且生成的dll也是在Debug文件夾目錄下。
要是想用Release生成的話,同上步驟便可。
構建成功後能夠在這裏找到
將.dll文件複製到以前Java代碼中System.out.println(System.getProperty("java.library.path"));這條語句輸出的路徑中任何一個文件夾下便可
最後回到myeclipse中運行Java程序,就能夠了
完成了這個調用後,就只須要將這個嵌入到javaweb工程中便可
有些時候調用dll須要返回int數組,或者字符串,我再分享這兩個方法
返回一個int數組
生成的頭文件用javah生成.h頭文件
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class Test_floatArray */ #ifndef _Included_Test_floatArray #define _Included_Test_floatArray #ifdef __cplusplus extern "C" { #endif /* * Class: Test_floatArray * Method: haha * Signature: ()[I */ JNIEXPORT jintArray JNICALL Java_Test_floatArray_haha (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
#include "Test.h" #include <iostream> JNIEXPORT jintArray JNICALL Java_Test_floatArray_haha (JNIEnv *env, jobject obj){ //1.新建長度len數組 jintArray jarr = env->NewIntArray(3); //2.獲取數組指針 jint *arr = env->GetIntArrayElements(jarr, NULL); //3.賦值 int i = 0; for (; i < 3; i++){ arr[i] = i; } //4.釋放資源 env->ReleaseIntArrayElements(jarr, arr, 0); //5.返回數組 return jarr; }
返回一個字符串型數組,首先須要用一個stojstring()函數,將c++的string類型轉換爲const char 類型,再從const char 轉化爲jstring類型,便可直接返回一個jstring類型
#include "test.h" #include <iostream> #include <string.h> using namespace std; jstring stoJstring(JNIEnv* env, const char* pat) { jclass strClass = env->FindClass("Ljava/lang/String;"); jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V"); jbyteArray bytes = env->NewByteArray(strlen(pat)); env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat); jstring encoding = env->NewStringUTF("utf-8"); return (jstring)env->NewObject(strClass, ctorID, bytes, encoding); } JNIEXPORT jstring JNICALL Java_com_action_upLoadAction_shibie (JNIEnv *env, jobject obj, jstring path1, jstring path2, jstring path3){ const char* str1 = env->GetStringUTFChars(path1, 0); const char* str2 = env->GetStringUTFChars(path2, 0); const char* str3 = env->GetStringUTFChars(path3, 0); printf("%s\n", str1); printf("%s\n", str2); printf("%s\n", str3); printf("你好\n"); string str = "好\#"; const char* chardata = str.c_str(); jstring jstr = stoJstring(env, chardata); return jstr; }
test.h文件內容以下:
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_action_upLoadAction */ #ifndef _Included_com_action_upLoadAction #define _Included_com_action_upLoadAction #ifdef __cplusplus extern "C" { #endif /* * Class: com_action_upLoadAction * Method: Contrast * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String; */ JNIEXPORT void JNICALL Java_com_action_upLoadAction_Contrast (JNIEnv , jobject , jstring , jstring, jstring); JNIEXPORT jstring JNICALL Java_com_action_upLoadAction_shibie (JNIEnv *, jobject, jstring, jstring, jstring); #ifdef __cplusplus } #endif #endif
關於java web,推薦去看個人另外一篇文章:https://segmentfault.com/a/11...
而後關於有些方法須要返回某個參數如String,boolean等,能夠參考這篇文章:
http://www.cnblogs.com/icejoy...