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 将本地的整数数组拷贝到传进来的参数中,以便传回