JAVA本地方法调用(2)数组参数传递

时间:2021-09-08 21:25:31

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