JNI学习笔记:数组作为函数参数



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 传入的数组array
  • jboolean *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);

猜你喜欢

转载自blog.csdn.net/cv_jason/article/details/79643532
今日推荐