1 前言
本文将展示如何从Java代码中,通过JNI接口传递给C++代码一维数组,并进行相关运算以及返回值。Java代码传递数组到C++中,主要通过JNI的函数来实现。
2 一维数组作为函数参数传值的Demo
2.1 代码示例
- Java代码
public class JNITest{
public static native float sumOfArray(float[] jf);
static{
System.loadLibrary("libmath");
}
public static void main(String args[]){
float[] jf = {0.5f,0.4f,0.3f,0.2f,0.1f};
System.out.println(sumOfArray(jf));
for(float f:jf){
System.out.print(f+" ");
}
}
}
- C++代码
#include<jni.h>
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(jfloat a, jfloat b){
return a < b;
}
JNIEXPORT jfloat JNICALL Java_JNITest_sumOfArray
(JNIEnv *env, jclass, jfloatArray jf){
jboolean jb = JNI_FALSE;
jfloat*jfloatPointer = env->GetFloatArrayElements(jf, &jb);
jsize length = env->GetArrayLength(jf);
jfloat sum = 0.0f;
// 对传递进来的数组进行求和
for (jsize i = 0; i < length; i++)
{
sum += jfloatPointer[i];
}
//对传递进来的java数组进行排序
sort(jfloatPointer, jfloatPointer + length, cmp);
env->ReleaseFloatArrayElements(jf, jfloatPointer, 0);
return sum;
}
注意:该C++代码要编译成dll,并且命名要与Java中的libmath库名相同
- 结果
我们可以看到,Java传递的数组求和以及排序都得以顺利实现,在C++代码内对Java代码产生的数组完成了修改。
2.2 程序分析
Java将数组通过public static native float sumOfArray(float[] jf)
传值给C++动态链接库libmath
,然后通过函数名找到对应函数地址,进行传值。JNI接口中的GetFloatArrayElements
函数负责接收该数组,并进行相关运算。
特别注意:在数组运算完之后,一定要释放内存,不然对数组的修改操作无效(实验结果,原理尚不清楚)。
2.3 函数释义
jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy)
jfloatArray array
传入的数组arrayjboolean *isCopy
返回值是否为数组拷贝副本,如果取值JNI_FALSE,意味着对原始字符串直接进行修改,如果取值JNI_TRUE,意味着操作的是一份副本,并不会改变字符串的原始值。jfloat*
返回的是一个jfloat的指针,用于操作传入的Java数组
jsize GetArrayLength(jarray array);
jsize
返回array数组的长度
void ReleaseFloatArrayElements(jfloatArray array, jfloat *elems,jint mode)
jfloatArray array
传入的Java数组jfloat *elems
释放的元素个数,即数组的大小jint mode
释放模式,可能与内存的分配模式(动态分配,静态分配)对应
3 数组作为返回值的Demo
3.1 代码示例
- Java代码
public class JNITest{
public static native float[] createArray(int length);
static{
System.loadLibrary("JNITest");
}
public static void main(String args[]){
float[] jf;
int length = 10;
jf = createArray(length);
for(float f:jf){
System.out.print(f+" ");
}
}
}
- C++代码
#include<jni.h>
#include<iostream>
#include<algorithm>
using namespace std;
JNIEXPORT jfloatArray JNICALL Java_JNITest_createArray
(JNIEnv *env, jclass thiz, jsize length){
jboolean jb = JNI_FALSE;
jfloatArray jfarray = env->NewFloatArray(length);
jfloat *jf = env->GetFloatArrayElements(jfarray, &jb);
for (jsize i = 0; i < length; i++)
{
jf[i] = 0.1*i;
}
// 这一行释放内存必须有,不然的话,数据修改无效
env->ReleaseFloatArrayElements(jfarray,jf,0);
return jfarray;
}
- 运行结果
从C++传递出来的数组,在Java代码层面得以显示。
3.2 函数释义
这个程序的核心只有一个函数:
jfloatArray NewFloatArray(jsize len);
jsize len
创建数组的大小jfloatArray
返回创建的Java数组
4 一维数组作为函数参数的总结
JNI处理Java数组的函数原型为:
NativeType *Get<PrimitiveType>ArrayElements(JNIEnv *env,
ArrayType array, jboolean *isCopy);
作用是得到传入Java数组的指针,通过指针进行操作。
文件jni.h中声明了具体函数原型,整理如下表:
序号 | 函数原型 | 注释 |
---|---|---|
1 | jboolean * GetBooleanArrayElements(jbooleanArray array, jboolean *isCopy); | 布尔型数组 |
2 | jbyte * GetByteArrayElements(jbyteArray array, jboolean *isCopy); | Byte数组 |
3 | jchar * GetCharArrayElements(jcharArray array, jboolean *isCopy) ; | char数组 |
4 | jshort * GetShortArrayElements(jshortArray array, jboolean *isCopy); | short数组 |
5 | jint * GetIntArrayElements(jintArray array, jboolean *isCopy); | int数组 |
6 | jlong * GetLongArrayElements(jlongArray array, jboolean *isCopy); | long数组 |
7 | jfloat * GetFloatArrayElements(jfloatArray array, jboolean *isCopy); | float数组 |
8 | jdouble * GetDoubleArrayElements(jdoubleArray array, jboolean *isCopy) | double数组 |
同理,创建数组的函数原型为:
ArrayType New<PrimitiveType>Array(JNIEnv *env, jsize length);
释放数组内存的函数原型为:
void Release<PrimitiveType>ArrayElements(JNIEnv *env,
ArrayType array, NativeType *elems, jint mode);