Java與C++之JNI編程小結

1.       什麼是 JNI java

    JNIJava Native Interface的縮寫。從Java 1.1開始,JNI標準成爲java平臺的一部分,它容許Java和其餘語言進行交互。JNI一開始爲CC++而設計的,可是它並不妨礙你使用其餘語言,只要調用約定受支持就能夠了。 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++ 之間互調了

相關文章
相關標籤/搜索