JNI之对象数组使用

NDK  代码片段  2023年7月27日 am8:08发布1年前 (2023)更新 城堡大人
104 0 0

前言

上一篇《JNI之数组简单操作》介绍的是jintArray的使用,今天就介绍对象数组

  jarray                (数组)
    jobjectArray         (object数组)
    jbooleanArray        (boolean数组)
    jbyteArray           (byte数组)
    jshortArray          (short数组)
    jintArray            (int数组)
    jlongArray           (long数组)
    jfloatArray          (float数组)      
    jdoubleArray         (double数组)

其实数组的使用都差不多,但jobjectArray看起来较特殊,就单独拎出来。

正文

这里以Integer[]为例哈,顺带复现一下《JNI之访问方法和域》的使用。

Signature(签名)

#java
#签名:([Ljava/lang/Integer;)[Ljava/lang/Integer;
public static native Integer[] native_sortInteger(Integer[] buffer);

如何还对Signature(签名)获取不太理解,推荐在看看《JNI静态注册》。这里还是在之前《动态注册》基础修改。

/**
 * 定义Java和JNI函数的绑定表
 * 方法数组,分别为:(native方法 , 方法签名 , 函数指针[JNI中需要实现的方法名])
 * 通过javac和javap 获取 方法签名
 */
JNINativeMethod method_table[] = {
  {"native_sortInteger", "([Ljava/lang/Integer;)[Ljava/lang/Integer;", (void *) native_sort_integer},
};

涉及函数

# 查找class引用
jclass      (*FindClass)(JNIEnv*, const char*);
# 获取方法ID
jmethodID   (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
# 同方法ID调用java方法
jint        (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
# 获取域(变量)ID
jfieldID    (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);
# 获取域ID对应的值
jint        (*GetIntField)(JNIEnv*, jobject, jfieldID);
# 改变域ID对应的值
void        (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);
# 获取数组长度
jsize       (*GetArrayLength)(JNIEnv*, jarray);
# 获取指定位置的对jobject
jobject     (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);
# 改变指定位置的jobject
void        (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);

代码片段

下面是native_sort_integer的实现代码。

看起来有点复杂,其实就是两个功能

  1. 计算数组中的sum

  2. 排序

由于这里用的是Integer对象,因此需要find到Integer的类引用,有两种方式获取Integer中的值,一个是通域ID(属性ID)value,另外一个是通过方法ID。

JNIEXPORT jobjectArray
JNICALL native_sort_integer(JNIEnv *env , jclass clazz, jobjectArray integerArray){
    jclass integerClass = env->FindClass("java/lang/Integer");
    if( NULL == integerClass ){
        LOGE("native_printf_integer integerClass(NULL)");
        return NULL;
    }
    //intValue是Java中Integer的方法
    jmethodID intValueMethodID = env->GetMethodID(integerClass, "intValue", "()I");
    if( NULL == intValueMethodID ){
        LOGE("native_printf_integer intValue(NULL)");
        return NULL;
    }
    //value通过Integer的变量
    jfieldID valueFieldID = env->GetFieldID(integerClass, "value", "I");
    if( NULL == valueFieldID ){
        LOGE("native_printf_integer valueFieldID(NULL)");
        return NULL;
    }
    //获取integerArray长度
    jsize length = env->GetArrayLength(integerArray);
    LOGE("native_printf_integer length(%d)", length);
    if (length <= 0) {
        return NULL;
    }
    int i = 0;
    int sum = 0;
    jint array[length];
    for (i = 0; i < length; i++) {
        jobject object = env->GetObjectArrayElement(integerArray, i);
        if( NULL != object){
            // 1. value值通过jmethodID获取[这里注释掉了]
            //sum += env->CallIntMethod(object, intValueMethodID);
            // 2. value值通过jfieldID直接获取
            jint value = env->GetIntField(object, valueFieldID);
            sum += value;
            array[i] = value;
        }
    }
    //打印SUM值
    LOGE("native_printf_integer sum(%d)", sum);
    //从大到小排序
    int j = 0;
    int temp = 0;
    for (i = 0; i < length - 1; i++) {
        for (j = i + 1; j < length; j++) {
            if (array[i] < array[j]) {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
    //重新赋值给jobjectArray
    for (j = 0; j < length; j++) {
        jobject object = env->GetObjectArrayElement(integerArray, j);
        if( NULL != object){
            //通过jfieldID
            env->SetIntField(object, valueFieldID, array[j]);
        }
    }
    return integerArray;
}

上面是重新赋值给integerArray,我们也可以重新创建新的jobjectArray。

在上面基础上修改,赋值那部分进行替换即可。

//创建Integer的jobjectArray,并把array赋值给新的对象数组
jobjectArray newIntegerArray = env->NewObjectArray(length, integerClass, NULL);
jobject integerObject = NULL;
for (j = 0; j < length; j++) {
    //创建jobject对象
    integerObject = env->AllocObject(integerClass);
    //给jobject赋值
    env->SetIntField(integerObject, valueFieldID, array[j]);
    //创建的jobject赋值到新的数组中
    env->SetObjectArrayElement(newIntegerArray, j, integerObject);
}
//释放局部引用
env->DeleteLocalRef(integerObject);

参考文章

  1. JNI之访问方法和域

  2. NDK中jni.h头文件完整内容

  3. JNI 中创建对象数组

 历史上的今天

  1. 2022: [摘]Typora破解和下载(仅供学习)(0条评论)
  2. 2021: 西贝:路人(0条评论)
  3. 2020: [摘]音视频学习系列第(一)篇---基础概念(0条评论)
  4. 2019: 普希金:我曾经爱过你(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

[摘]WindowManger层级记录

前言记录一下Android中WindowManger的层级相关知识。摘抄于此,方便自己查阅。本文摘抄于《Android中WindowManger的层级分析》正文Window 分类应用 Window(ApplicationWindow: 对应一个 Acitivity)子 Window...

Android中ImageView半边圆角处理记录2

前言之前介绍过对ImageView进行圆角处理,具体文章《Android中ImageView半边圆角处理记录 -笔友城堡 - 阅读是一种生活方式 ()》,后面发现网上还有一种更简单的一种方式。有点:代码少,简单缺点:边界不够圆滑(存在锯齿)正文具体效果如下(左侧是RoundImage...

ViewPager禁止左右滚动

前言项目中需要用ViewPager+Fragment组合使用,比如很见的就是图片暂时。每个客户需求不一样,有些需要左右滑动,有序不需要,因此需要禁止左右滑动切换界面。本文代码是摘的,也验证OK,感谢分享。正文直接上代码,要介绍的可以看摘抄的文章。public class NoScroll...

《人间值得》前言

大家好,我是中村恒子,今年90岁,从事心理(精神科)医生工作将近70年了。因为是医生,所以和大家一样每天朝九晚五地工作。与其说我仍在工作,倒不如说是被要求工作。说实话,我真心感谢信任我的患者朋友,这样我能在工作中有机会与各种各样的人交流。每个人都会有烦恼,在人世间,我们各有各的烦恼。其中,既有职...

希区柯克:机舱里的钟声

从明尼苏达州杜鲁门城飞往华盛顿的班机上,坐在我旁边靠窗座位上的那个大高个子,看着手腕上的表说:“七点十分,托尼,我们已飞一半路了,假如我逃亡海外的话,他们会认为我不回来了。”“山姆,你不是在逃亡。”我说。他微微一笑,赞同地说:“对,我不是在逃亡。”就从那时候起,从头顶传来“滴答,滴答”的声音。...

梁启超:最苦与最乐

人生什么事最苦呢?贫吗?不是。失意吗?不是。老吗?死吗?都不是。我说人生最苦的事,莫苦于身上背著一种未了的责任。人若能知足,虽贫不苦;若能安分(不多作分外希望),虽然失意不苦;老、死乃人生难免的事,达观的人看得很平常,也不算什么苦。独是凡人生在世间一天,便有一天应该的事。该做的事没有做完,便像...