IntelliJ idea 2018 平臺下JNI程式設計呼叫C++演算法(一)
本文環境:IntelliJ idea2018.2+Visual Studio 2017
專案:JavaWEB+Win32控制檯
宣告:本人是個新手小白。因為專案是C++演算法寫的,但是要用網頁呼叫,所以先學習JavaWEB呼叫C++程式作為嘗試。參考了網上的一些教程,結合自己的理解與出現的錯誤,寫成總結日後參考。不足之處請提出。
首先明確本文的步驟:
- 在Java中新建一個類。
- 生成JNI標頭檔案。(此處有兩種方法:2.1手動輸入javah命令生成標頭檔案、2.2 一鍵生成標頭檔案)
- 在VS2017下引入標頭檔案。
- 將dll新增進JavaWEB工程,成功執行。
1.在Java中新建類
利用IntelliJ idea新建一個Java工程,在src中新建一個Java類,名稱命名“testNative”。之後彈出testNative.java。
在testNative.java中寫如下程式:
函式System.loadLibrary()是載入dll(windows)或so(Linux)庫,只需名稱即可,無需加入檔名字尾(.dll或.so)。
native關鍵字將函式sayHello()宣告為本地函式,由C/C++實現。具體的實現就在hello.dll(Windows平臺)或hello.so(Linux平臺)中。
2.生成JNI標頭檔案
- 2.1 手動輸入javah命令生成標頭檔案
- 2.2 一鍵生成標頭檔案
2.1 手動輸入javah命令生成標頭檔案
JNI生成標頭檔案是通過JDK中提供的javah來完成,javah在 {JDKHome}/bin
目錄中。用法如下:
javah -jni -classpath (搜尋類目錄) -d (輸出目錄) (類名)
例如,將E:\Porject\out\com\huachao\java
目錄中的HelloJNI.class
生成標頭檔案,並放入到E:\Project\jni
中:
javah -jni -classpath E:\Porject\out\com\huachao\java -d E:\Project\jni com.huachao.java.HelloJNI.java
需要注意的是,使用javah來生成標頭檔案(.h)時,-classpath指定的是編譯後的java檔案(.class)的目錄,而不是原始檔(.java)的目錄,因此在使用javah指令之前,先build一下專案(或直接執行一下)。此時會生稱out目錄,所有編譯後的檔案都會存放在這個目錄中。
Build之後:project下的out中多出來production及以下內容。
生成out目錄之後的:
接下來,直接在IDEA的Terminal視窗執行javah,寫命令如下:
(沒有Terminal視窗的可以在File→Plugins→Terminal 勾選它,點選Apply,點選Restart即可
如果是要啟動terminal則必須先做完上面動作,才可以點選Tools→Open Terminal... 來達到開啟terminal)
javah -jni -classpath (搜尋類目錄) -d (輸出目錄) (類名)
按回車鍵執行,在終端(Terminal)輸入如上命令之後,目錄出現了jni資料夾,下面對應有標頭檔案。
開啟testNative.h, 函式名稱是有規律的,即Java_<
包
>_<
類名
>_<
函式名
>
接下來我們就要實現。
至此,生成標頭檔案的第一種方法就結束了。還有另一種一鍵生成的方法更簡單請往下看。
2.2 一鍵生成標頭檔案
如果目錄層次很深,或者是有多個需要生成標頭檔案的class檔案,這工作量太大了,當然你可以通過寫個小程式來實現。
但是這裡有個更便捷的方法。點選File>Settings>Tools>External Tools
:
新增一個新的External Tools:
在testNative.java檔案中 點選右鍵>External Tools>Generate Header File
,
點選生成,可以看到Terminal視窗會自動執行指令。跟2.1小節的指令一模一樣。
3.在VS2017下引入標頭檔案
首先開啟Visual Studio 2017,新建一個Win32控制檯。
Win32專案現在位於“新建專案”對話方塊中的Windows桌面類別下面,在此類別下面還有一個新的Windows桌面嚮導,可以建立新的Win32專案
雙擊 Windows桌面嚮導,開啟如下
注意此處不要勾選預編譯標頭。
初始目錄:
拷貝三個.h檔案到VS專案中:
將在Java JDK的安裝目錄下,我的目錄為C:\Program Files\Java\jdk1.8.0_181\include下的jni.h,
與C:\Program Files\Java\jdk1.8.0_181\include\win32下的jni_md.h,
與第一步生成的testNative.h, 一共三個標頭檔案,拷貝到當前VS專案目錄下,拷貝之後的目錄為:
將testNative.h中的 #include<jni.h> 改為 #include”jni.h”
在原始檔目錄下新建.cpp檔案,起名main.cpp。寫入程式:
#include "testNative.h"
#include "jni.h"//注意新增這句
#include<iostream>
using namespace std;
JNIEXPORT void JNICALL Java_testNative_sayHello(JNIEnv *env, jobject obj)
{
cout << "Hello World!" << endl;
cout << "I come from C++!" << endl;
}
另外,注意,在右側目錄中 右擊 解決方案-配置管理器
將Debug改成64位,因為我的IntelliJ idea是64位下的。這樣改動之後生成的dll可以用在64位平臺下。
之後按F5執行,執行成功如圖所示。
顯示生成的dll的路徑。找到此dll,複製。
4.將dll新增進JavaWEB工程中
將複製得到的dll改名為“hello.dll”,將其拷貝到JavaWeb專案目錄下,如圖所示:
之後執行專案,可以在控制檯輸出中看到如下圖所示結果,表示成功。
5.可能出現的錯誤
1.【注意事項】:如果你建的C++工程時32位的,當然Win32就是32位的工程,生成的dll只能執行在32位的JDK上。如果你的Java JDK是64位的,那麼你新建Win32控制檯程式後,在專案屬性中修改平臺為64位即可。若不修改,出現如下錯誤:
2.第一次新建Win32控制檯選擇了預編譯表頭,如下圖所示:
在寫main.cpp時候執行出現如下錯誤:
注意不勾選 預編譯標頭。
3.【注意事項】將testNative.h中的#include<jni.h>改為#include”jni.h”。
寫在最後:新手起步,不斷學習總結。參考了網路資料,有問題提出大家共同交流!
轉載請註明出處,謝謝^_^