JNI
(Java Native Interface),即Java本地介面,是為java編寫本地方法和jvm嵌入本地應用程式的標準的應用程式介面。首要的目標是在給定的平台上採用JAVA通過JNI
調
用本地方法,而本地方法是以庫檔案的形式存放的(在WINDOWS平台上是DLL檔案形式,在UNIX機器上是SO檔案形式)。通過調用本地的庫檔案的內
部方法,使JAVA可以實現和本地機器的緊密聯絡,調用系統級的各介面方法。有的jvm來實現相容的二進位編碼本地方法庫。
簡敘步驟
·編寫帶有native聲明的方法的java類
·使用javac命令編譯所編寫的java類
·使用javah
java類名產生副檔名為h的標頭檔
·使用C/C++實現本地方法,並產生動態串連庫
·將庫檔案拷貝到java工程目錄下,運行java程式
1 建立java工程
在JAVA程式中,首先需要在類中聲明所調用的庫名稱,如下:
static {
System.loadLibrary(“lidptest”);
}
庫的副檔名字可以不用寫出來,究竟是DLL還是SO,由系統自己判斷。接著對將要調用的方法做本地聲明,關鍵字為native。並且只需要聲明,而不需要具 體實現。如下:
public native static void fn1(int i);
public native static int fn2(void );
然後編譯該JAVA程式檔案,產生CLASS,再用JAVAH
命令,JNI
就會產生C/C++的標頭檔。
例如建立java檔案TestDel.java,內容為:
public class TestDel
{
static
{
System.loadLibrary("lidp"); //庫名cjw
}
public native static void creFolder();
public native static void delFolder1();
public native static void delFolder2();
public static void main(String[] args)
{
TestDel test = new TestDel();
System.out.println("start create Folder...");
test.creFolder();
System.out.println("create Folder finished.");
long stime = System.currentTimeMillis();
//test.delFolder1();
test.delFolder2();
long etime =System.currentTimeMillis();
System.out.println(etime-stime);
}
}
用javac TestDel.java編譯它,產生TestDel.class。
再用javah
TestDel,則會在目前的目錄下產生TestDel.h檔案,這個檔案需要被C/C++程式調用來產生所需的庫檔案。
2 產生動態連結程式庫
對於已產生的.h標頭檔,C/C++所需要做的,就是把它的各個方法具體的實現。然後編譯串連成庫檔案。
接上例子。我們先看一下TestDel.h檔案的內容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni
.h>
/* Header for class TestDel */
#ifndef _Included_TestDel
#define _Included_TestDel
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: TestDel
* Method: creFolder
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_TestDel_creFolder
(JNIEnv *, jclass);
/*
* Class: TestDel
* Method: delFolder1
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_TestDel_delFolder1
(JNIEnv *, jclass);
/*
* Class: TestDel
* Method: delFolder2
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_TestDel_delFolder2
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
在具體實現的時候,我們只關心幾個函數原型 :
JNIEXPORT void JNICALL Java_TestDel_creFolder
(JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_TestDel_delFolder1
(JNIEnv *, jclass);
JNIEXPORT void JNICALL Java_TestDel_delFolder2
(JNIEnv *, jclass);
這裡JNIEXPORT和JNICALL都是JNI
的關鍵字,表示此函數是要被JNI
調用 的。如果java中申明的函數原型包含參數,例如int,那麼產生的標頭檔中變成jint,它是以JNI
為
中介使JAVA的int類型與本地的int溝通
的一種類型,我們可以視而不見,就當做int使用。其它參數類似。函數的名稱是JAVA_再加上java程式的package路徑再加函數名組成的。參數
中,我們也只需要關心在JAVA程式中存在的參數,至於JNIEnv*和jclass我們一般沒有必要去碰它。
好,下面我們使用dll具體實現這幾個函數(一個函數是建立目錄,另兩個是兩種刪除目錄的方法)。
注
意,本例是通過VS2005建立dll的,需要安裝"WebDeploymentSetup.msi", New一個工程選擇VC++建立win32
project,選中dll建立Empty
project。將java中產生的標頭檔拷貝至此工程添加,再建立新檔案test.cpp(必須以cpp尾碼,若以c尾碼則builder會出
錯)test.cpp代碼如下(注意這句#include "TestDel.h"):
#include <stdio.h>
#include <direct.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include "TestDel.h"
JNIEXPORT void JNICALL Java_TestDel_creFolder(JNIEnv *, jclass)
{
int i,j;
char buf1[20];
char buf2[20]="./Folder/";
char buf3[20];
mkdir("Folder");
for(i=0;i<100;i++)
{
itoa(i,buf1,10);
mkdir(strcat(buf2,buf1));
strcpy(buf3,strcat(buf2,"//"));
for(j=0;j<100;j++)
{
itoa(j,buf1,10);
mkdir(strcat(buf2,buf1));
strcpy(buf2,buf3);
}
strcpy(buf2,"./Folder/");
}
}
JNIEXPORT void JNICALL Java_TestDel_delFolder1
(JNIEnv *, jclass)
{
int i,j;
char buf1[20];
char buf2[20]=".//Folder//";
char buf3[20];
for(i=0;i<100;i++)
{
itoa(i,buf1,10);
strcat(buf1,"//");
strcpy(buf3,strcat(buf2,buf1));
for(j=0;j<1000;j++)
{
itoa(j,buf1,10);
rmdir(strcat(buf2,buf1));
strcpy(buf2,buf3);
}
rmdir(buf3);
strcpy(buf2,".//Folder//");
}
}
JNIEXPORT void JNICALL Java_TestDel_delFolder2
(JNIEnv *, jclass)
{
char cmd[50];
strcpy(cmd,"rmdir /s/q ");
strcat(cmd,"Folder");
system(cmd);
}
注
意:一定要把SDK中的include文
件夾中(和它下面的win32檔案夾下的標頭檔)的幾個標頭檔拷貝到VC的include檔案夾中。或者在VS的tools/options
-〉Projects and Solutions/VC++ Project
Settings,修改directories中include的設定,把標頭檔../sdk1.5.0/inlcude 和
../sdk1.5.0/include/win32給包含進來。
編譯串連成庫檔案dll(在debug檔案夾中),注意名稱要與JAVA中需要調用庫名的一致,這裡可以修改為lidp.dll。
3 運行程式
把lidp.dll拷貝到TestDel.class的目錄下,java TestDel運行它,就可以觀察到結果了。這裡實現的功能是統計刪除檔案夾的時間。
java中有一種直接把c C++代碼轉換成java類的工具 swig 很方便。