1. 什麼是 JNI java
JNI是Java Native Interface的縮寫。從Java 1.1開始,JNI標準成爲java平臺的一部分,它容許Java和其餘語言進行交互。JNI一開始爲C和C++而設計的,可是它並不妨礙你使用其餘語言,只要調用約定受支持就能夠了。 ios
使用java與本地已編譯的代碼交互,一般會喪失平臺可移植性。可是,有些狀況下這樣作是能夠接受的,甚至是必須的,好比,使用一些舊的庫,與硬件、操做系統進行交互,或者爲了提升程序的性能。 windows
關於 JNI 的用法很簡單,有點像 java 裏的 reflect 的工做機制,有興趣的朋友能夠參看更詳細的書 數組
2. JNI 開發步驟 eclipse
l 編寫帶有native聲明的方法的java類 性能
l 使用javac 或 IDE(JBuilder,eclipse等)編譯所編寫的java類 ui
l 使用javah -jni java類名生成擴展名爲h的頭文件 this
l 使用C++ 實現本地方法,對調用簽名可用 javap –s –p [類全名] 查看(開發 C++ 動態連接庫本例是用的 VC6) spa
注意要從 JDK下面的 include 文件夾中把 jni.h和 jni_md.h 兩個文件 copy 到你的 VC 工程裏 操作系統
l 在 Java 中 load 動態連接庫文件,調用 native 方法
3. 開發實例
1. 編寫 Java 類: (個人 IDE 是 eclipse)
/**
* Jack.Wang
*/
package org.jm.jni;
import java.util.ArrayList;
/**
* @author Jack.Wang
* @time Mar 1, 2008
*/
public class BackgroundProcess {
static {
System.loadLibrary("org_jm_jni_BackgroundProcess");
}
// 三個 native 方法和一個 int 變量
public native boolean checkValid();
public native void processData(BackgroundProcess bg);
public native void processGarbage(String[] bg);
public int num = 5;
// C++ 中能夠調用的方法
public String backProcess(ArrayList<String> p) {
System.out.println("這是 Java 裏的方法,在 C++ 中調用。");
System.out.println("這個方法,是 java 中 native checkValid 方法調用的。");
return "look up process ->" + p;
}
public static void main(String[] args) {
String[] array = new String[4];
array[0] = "jack";
array[1] = "maggie";
array[2] = "rocket";
array[3] = "tom";
BackgroundProcess bgP = new BackgroundProcess();
// 調用 C++ DLL 中定義的方法。
bgP.checkValid();// 該方法回調 java 中的 backProcess 方法
bgP.processData(bgP);
bgP.processGarbage(array);
// C++ DLL 改變了該變量
System.out.println("number 如今的值是: " + bgP.num);
}
}
2. 生成 C++ 的頭文件(javah 命令生成,用javap –s –p [類全名] 命令查看java 方法簽名)
/* DO NOT EDIT THIS FILE - it is machine generated */
#include "jni.h"
/* Header for class org_jm_jni_BackgroundProcess */
#ifndef _Included_org_jm_jni_BackgroundProcess
#define _Included_org_jm_jni_BackgroundProcess
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: org_jm_jni_BackgroundProcess
* Method: checkValid
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_org_jm_jni_BackgroundProcess_checkValid
(JNIEnv *, jobject);
/*
* Class: org_jm_jni_BackgroundProcess
* Method: processData
* Signature: (Lorg/jm/jni/BackgroundProcess;)V
*/
JNIEXPORT void JNICALL Java_org_jm_jni_BackgroundProcess_processData
(JNIEnv *, jobject, jobject);
/*
* Class: org_jm_jni_BackgroundProcess
* Method: processGarbage
* Signature: ([Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_org_jm_jni_BackgroundProcess_processGarbage
(JNIEnv *, jobject, jobjectArray);
#ifdef __cplusplus
}
#endif
#endif
3. 開發 C++ DLL 的原文件 (記得要加入 jni.h 和 jni_md.h 兩個文件)
發佈 DLL 文件, 我是配置了 path 環境變量
#include "org_jm_jni_BackgroundProcess.h"
#include <iostream.h>
#include <windows.h>
#include "string.h"
char* jstringTostring(JNIEnv* env, jstring jstr)
{
char* rtn = NULL;
jclass clsstring = env->FindClass("java/lang/String");
jstring strencode = env->NewStringUTF("utf-8");
jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
jsize alen = env->GetArrayLength(barr);
jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
if (alen > 0)
{
rtn = (char*)malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
env->ReleaseByteArrayElements(barr, ba, 0);
return rtn;
}
//char* to jstring
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);
}
/*
* Class: org_jm_jni_BackgroundProcess
* Method: checkValid
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_org_jm_jni_BackgroundProcess_checkValid
(JNIEnv *env, jobject obj){
jclass bgpClass=env->GetObjectClass(obj);
jmethodID methodId=env->GetMethodID(bgpClass,"backProcess","(Ljava/util/ArrayList;)Ljava/lang/String;");
jobject str=env->CallObjectMethod(obj,methodId,NULL);
jfieldID fieldId=env->GetFieldID(bgpClass,"num","I");
jint number=env->GetIntField(obj,fieldId);
cout << "number 值是: " <<number << endl;
env->SetIntField(obj,fieldId,100L);
return 1;
}
/*
* Class: org_jm_jni_BackgroundProcess
* Method: processData
* Signature: (Lorg/jm/jni/BackgroundProcess;)V
*/
JNIEXPORT void JNICALL Java_org_jm_jni_BackgroundProcess_processData
(JNIEnv *env, jobject, jobject){
cout<< "this function do nothing " << endl;
}
/*
* Class: org_jm_jni_BackgroundProcess
* Method: processGarbage
* Signature: ([Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_org_jm_jni_BackgroundProcess_processGarbage
(JNIEnv *env, jobject, jobjectArray array){
jint size=env->GetArrayLength(array);
cout << "數組大小是: " << size << endl;
jstring tempObj=NULL;
char *pszSTR1 = NULL;
for(int i=0;i<size;i++){
cout << "current value is : " << i << endl;
tempObj=(jstring)env->GetObjectArrayElement(array,i);
const char * chars =env->GetStringUTFChars(tempObj, 0);
cout << chars << endl;
}
}
4. 如今你能夠在 Java 和 C++ 之間互調了