1. 程式人生 > >JAVA本地方法呼叫(2)陣列引數傳遞

JAVA本地方法呼叫(2)陣列引數傳遞

JAVA可以把陣列作為引數傳遞給本地方法,在本地方法中可以訪問陣列中的元素。

不過,在本地方法卻不能直接訪問傳進來的陣列,需要進行一定的轉換。舉例說明:

1、建立 JAVA 類:

package test;
 
public class Test {
    public native void copy(int[] a, int[] b);
    
    public static void main(String[] args){
        System.load("/root/mycodes/native/intArrayCpy/Test.so");
        
        Test obj = new Test();
        int[] a = new int[]{1, 2, 3, 4, 5};
        int[] b = new int[a.length];
        
        obj.copy(a, b);
        String pre = "\r\n\r\n";
        for(int i : b){
            System.out.print(pre + i);
            pre = ", ";
        }
        System.out.println();
    }
}

2、編譯並生成 .h 檔案:

javac -d . Test.java
javah -jni test.Test


3、編寫 c 源程式,可以將 javah 生成的檔案拷貝成 c 檔案,然後在上面修改:

cp test_Test.h test_Test.c
vim test_Test.c


修改之後的C源程式如下:

#include <jni.h>
/* Header for class test_Test */
 
#ifndef _Included_test_Test
#define _Included_test_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     test_Test
 * Method:    copy
 * Signature: ([I[I)V
 */
JNIEXPORT void JNICALL Java_test_Test_copy
  (JNIEnv * env, jobject obj, jintArray pA, jintArray pB){
    int a[5];
    int b[5];
    int i;
    jsize size = (*env)->GetArrayLength(env, pA);
    (*env)->GetIntArrayRegion(env, pA, 0, size, a);
    for(i=0; i<5; i++){
        b[i] = a[i];
    }
    
    (*env)->SetIntArrayRegion(env, pB, 0, 5, b);
}
 
#ifdef __cplusplus
}
#endif
#endif

4、編譯並執行:
 gcc -I/usr/java/jdk1.7.0/include/ -I/usr/java/jdk1.7.0/include/linux -fPIC -shared -o Test.so test_Test.c
java test.Test


注意在 Test.java 檔案中,System.load 中的引數是由上面的 gcc 命令生成的 so 檔案的全路徑

觀察發現,如果要訪問由JAVA虛擬機器傳進來的陣列,必須呼叫 env 提供的函式進行轉換。在 jdk 安裝目錄下查詢 jni.h 檔案,可以發現jdk其實為我們定義了很多轉換函式。比如上面的程式碼中用到了:

GetArrayLength 得到傳入的陣列引數的元素個數

GetIntArrayRegion 將JAVA虛擬機器傳進來的整數陣列元素拷貝到本地的整數陣列

SetIntArrayRegion 將本地的整數陣列拷貝到傳進來的引數中,以便傳回