(四)JNI 访问数组、异常

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

一、JNI 访问数组

1.访问基本类型数组

C:

JNIEXPORT jbyteArray JNICALL Java_com_xiaoyue_JNIString_testArray
(JNIEnv *env, jobject jobj, jintArray intArray) {
    int compare(jint * a, jint *b);
    //jintArray -> jint *
    jint *elemts = (*env)->GetIntArrayElements(env, intArray, NULL);
    if (elemts == NULL)
    {
        return;
    }
    //数组长度
    int len = (*env)->GetArrayLength(env, intArray);
    qsort(elemts, len, sizeof(jint), compare);
    //释放可能的内存
    //将JNI  修改的数据重新写回原来的内存
    (*env)->ReleaseIntArrayElements(env, intArray, elemts, JNI_COMMIT);
}

int compare(jint * a, jint *b) {
    return *a - *b;
}

这是传入一个 int 数组,进行快速排序,并返回。

jint *elemts = (*env)->GetIntArrayElements(env, intArray, NULL);

GetIntArrayElements 是对 jintArray 进行数组转换,转换为 C 语言中的 int 数组。获取其他类型数据数组方法类似。

int len = (*env)->GetArrayLength(env, intArray);

GetArrayLength 获取数组长度。

(*env)->ReleaseIntArrayElements(env, intArray, elemts, JNI_COMMIT);

ReleaseIntArrayElements 会释放缓存区(如果有的话),同时将 JNI 修改的数据重新写回原来的内存。

这边的快速排序采用的是 C 自带的 qsort 函数进行快速排序。

2.访问引用数据类型的数组

C:

JNIEXPORT jobjectArray JNICALL Java_com_xiaoyue_JNIString_testArray
(JNIEnv *env, jobject jobj, jobjectArray result) {

    int i;
    int size = (*env)->GetArrayLength(env, result);
    jclass jclz = (*env)->FindClass(env, "java/lang/String");

    if (jclz == NULL) {
        return NULL;
    }

    // 赋值
    for (i = 0; i < size; i++) {
        //C 字符串
        char * c_str = (char *)malloc(256);
        memset(c_str, 0, 256);
        //将 int 转换成为 char
        sprintf(c_str, "C: %d\n", i);
        //C ->jstring
        jstring str = (*env)->NewStringUTF(env, c_str);
        if (str == NULL) {
            return NULL;
        }
        //将jstring 赋值给数组
        (*env)->SetObjectArrayElement(env, result, i, str);
        free(c_str);
        c_str = NULL;
    }

    //返回jobjectArray
    return result;
}

这是对传进来的字符串数组进行修改。

(*env)->SetObjectArrayElement(env, result, i, str);

SetObjectArrayElement 对数组具体摸个位置的值进行修改。

二、异常

java:

public class JNIMain {

    public native void exception();

    static{
        System.loadLibrary("FirstApplication");
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        JNIMain jniMain = new JNIMain();

        jniMain.exception();
        System.out.println("jni exception");
    }
}

C:

JNIEXPORT void JNICALL Java_com_xiaoyue_JNIMain_exception
(JNIEnv *env, jobject jobj) {
    jclass cls = (*env)->GetObjectClass(env, jobj);
    jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");

    printf("exception\n");
}

结果:
这里写图片描述

在 C 中获取属性 key,由于没有这个属性,报错。但是报错后, C 后面的代码可以继续执行,而 java 后面的代码不能继续。即使手动给 java 加上 try、catch 也是无法捕捉到异常。

这时候需要 C 语言创建一个异常并抛出来,同时在 java 层进行 try、catch 处理。

java:

public class JNIMain {

    public native void exception();

    static{
        System.loadLibrary("FirstApplication");
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        JNIMain jniMain = new JNIMain();

        try {

            jniMain.exception();
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println(e.toString());
        }
        System.out.println("jni exception");
    }
}

C :

JNIEXPORT void JNICALL Java_com_xiaoyue_JNIMain_exception
(JNIEnv *env, jobject jobj) {
    jclass cls = (*env)->GetObjectClass(env, jobj);
    jfieldID fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");

    //检查是否发生异常
    jthrowable ex = (*env)->ExceptionOccurred(env);
    // 判断异常是否发生
    if (ex != NULL) {
        jclass newExc;
        //清空 JNI 产生的异生
        (*env)->ExceptionClear(env);
        //IllegalArgumentException
        newExc = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
        if (newExc == NULL)
        {
            printf("exception\n");
            return;
        }
        (*env)->ThrowNew(env, newExc, "Throw exception from JNI: GetFieldID faild ");
    }
}

结果:
这里写图片描述

这样,java 代码可以继续往下执行。可以在 C 语言中对异常处理进行封装成一个工具类进行使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值