Java采用JNI調用VC++生成的dll
應項目需求,需要android調用java,java再調用C++實現android一個圖片匹配的功能,我們作為java組需要和C++和Android進行交互。下面是java和C++采用JNI的方式進行接口傳參交互,我做的一個demo并運行成功。
什么是JNI?
JNI 全拼是Java Native Interface,中文意思為Java本地調用。JNI標準是Java平臺的一部分,它允許java和其他語言的代碼進行交互。JNI開始是為了本地已經編譯好的語言,尤其是C和C++而設計的,我們也可以使用JNI和其他語言進行溝通,我們只要調用約定受支持了就可以了。
什么原理?
我們知道C++中或者C#等.net都能生成.dll類庫,而C++(或.net)中生成的.dll文件,相當于我們java程序中java源代碼通過編譯生成的.class文件,我們在java程序中直接通過code調用C++的dll文件即可。
在 C語言中如果生成一個動態鏈接庫dll文件的時候,需要兩部分,一部分是為.h的頭文件,這個文件是負責對一些方法的聲明,而.cpp文件負責對方法的實現。而在java中,在JDK安裝目錄的include包中有個jni.h和jni_md.h,這個可以說是java發布的一個接口,在C++中可以直接使用這兩個head類型的文件對java要調用的C++方法編譯,讓java調用,并可以接收java傳遞過來的參數。直接上代碼啦。
具體的步驟如下所示(java發布一個接口,讓C++實現乘法的功能)
1、建立java源代碼如下所示。
建立java project,在src下建立com包,在com包下面建立我們的java類Reliability.java,代碼如下所示。
package com; public class Reliability { static { try { System.loadLibrary("Reliability"); // call dll } catch (UnsatisfiedLinkError e) { System.out.println("The load problem"); } } public native int shanfei(int i); public static void main(String[] args) { Reliability reliability = new Reliability(); System.out.print(reliability.shanfei(6)); } }
2、編譯.java源文件。
我們想實現傳遞int 整型參數來實現自己和自己相乘的結果,而實現shanfei(int p)方法的是C++。我們可以通過System.loadLibrary("Reliability")方法實現加載C++生成的dll,通過native聲明方法接口以及參數。
編寫好自己的Reliability.java代碼后,可以使用MyEclipse編譯為Reliability.class文件或者是直接用javac命令編譯為.class文件。
我的使用的MyEclipse進行編譯的,會在/Reliability/bin/com文件夾中生成Reliability.class文件。
3、用javah 命令讓Reliability.class文件生成C++需要的.h文件,也就是交給C++的接口。
在這里需要注意的是,一定要轉到你編譯成class文件的上一級目錄進行javah命令,并且你的JDK已經配置好環境變量,這里的環境變量為 JAVA_HOME:安裝jdk bin文件夾的上一級目錄,比如我的jdk安裝在C:\java\bin....,那我的JAVA_HOME為:C:\java 。path目錄:引用JAVA_HOME并且加上\bin ,為 %JAVA_HOME%\bin 。classpath為: .;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;這是一定要配置好的。然后在dos窗口如下編寫如下命令,生成給C++ .h的文件。
這樣在你的class文件上一級目錄中就會出現.h 的文件,并且引入到你的MyEclipse中,與com包同級。
4、這樣java已經給C++發布好了com_Reliability.h的頭文件,C++要去實現這個方法了。
因為要生成dll文件,所以我們需要建立動態鏈接庫文件,如果用的是C++ 6.0環境,就是建立projects --Dynamic-LInk Library工程。
之后添加我們的com_Reliability.h文件到我們的DLL項目中,目錄結構如下所示。
頭文件中的代碼如下所示,com_Reliability.h。
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_Reliability */ #ifndef _Included_com_Reliability #define _Included_com_Reliability #ifdef __cplusplus extern "C" { #endif /* * Class: com_Reliability * Method: shanfei * Signature: (I)I */ JNIEXPORT jint JNICALL Java_com_Reliability_shanfei (JNIEnv *, jclass, jint); #ifdef __cplusplus } #endif #endif
實現的Reliability.cpp代碼如下所示。
#include<jni.h> #include "com_Reliability.h" #include<stdio.h> #include<jni_md.h> JNIEXPORT jint JNICALL Java_com_Reliability_shanfei(JNIEnv *, jclass, jint p) { int j = p*p; return j; }
切忌:.cpp中和.h中的方法名一定要相同!!!并且把從java中找到的jni.h 和jni_md.h粘貼到外部依賴文件夾,或者直接放到VC98\include文件夾中。
5、生成dll文件
這樣我們ctrl+F7編譯,F7在C++項目的debug中生成Reliability.dll文件,這樣我們再把這個dll文件放到java編譯的.class目錄,同時放到MyEclipse與src同級。這樣運行java的Reliability.java文件,就看到C++給我們計算的結果了。顯示如下所示。
總結:
上述大致就是這個過程,在這個過程中會出現這樣或者那樣的問題,我也在不斷的去嘗試錯誤的所在,嘗試改動,最根本的就是計算機報錯了,就一定是自己哪個地方有錯誤,抱著這樣的心態,耐心的找答案、嘗試、思考,設置斷點調試,看到底是哪步出現的錯誤,最終會解決問題,讓你興奮的看到運行結果。