zoukankan      html  css  js  c++  java
  • JNI中修改(基本类型)参数并返回到Java层使用

      最近在JNI相关项目中遇到一个问题:在Java层传入多个int类型的参数,在jni层修改参数值或地址之后重新返回到Java层。这应该算是基本知识了,尤其是基本类型的参数往往看似简单,所以在之前学习jni时就一笔带过了,结果现在突然遇到这个问题竟然需要再查找资料学习,因此这周在重新复习一遍基础知识之后将此记录一下。走的再远,也不要忘记脚底的路。

      还是用Demo来解释下需求和对应解决方案吧

     1 public class LibraryManager {
     2 
     3     static{
     4         System.loadLibrary("libtest");
     5     }
     6 
     7     public final static native int add1(int arg1, int arg2, int result);
     8     public final static native int add2(int arg1, int arg2, int result);
     9   
    12 }

      在Java层写了两个方法分别模拟这个需求,在底层对arg1arg2参数做操作,之后将结果存入result中,希望能在Java层使用result,至于方法的返回值,则是模拟表示方法执行成功与否的标志位。

    下面分别在jni中用两种方式实现该需求,当然这两种都是典型错误的。

     1 JNIEXPORT jint JNICALL Java_com_xxx_LibraryManager_add1(
     2 JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jint jarg3){
     3     jarg3=jarg1+jarg2;
     4     LOGI("add1 arg3=%d", jarg3);
     5     return 1;
     6 }
     7 
     8 JNIEXPORT jint JNICALL Java_com_xxx_LibraryManager_add2(
     9 JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jint *jarg3){
    10     int result=jarg1+jarg2;
    11     jarg3=&result;
    12     LOGI("add2 arg3=%d", *jarg3);
    13     return 2;
    14 }

      如果还记得jni的运行原理的话,应该很容易理解这么写只是修改在c线程里边的参数值(add1()中)和参数地址(add2()中),至于Java层对应的参数没有变化,也就是说jni中的基本类型作为参数时只是形参传入的,对于上层没有任何影响。当然如果作为return值的话是绝对可以的,但是现在讨论的是作为参数值的方法。那么还是这个需求,应该怎么解决呢?

      在LibraryManager.class中增加两个新的方法

    1     public final static native int addConfirm1(int arg1, int arg2, int[] result);
    2     public final static native int addConfirm2(int arg1, int arg2, Integer result);

    看第三个参数就能知道解决方法了,将int类型转换为int[]addConfirm1()中)和int对应的整型类(addConfirm2()中),当然就是使用jni中的JNIEnv可以获取到的方法来修改参数,至于具体用法在下面详细列出。

     1 JNIEXPORT jint JNICALL Java_com_bob_testlib_LibraryManager_addConfirm1(
     2 JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jintArray jarg3){
     3     int result=jarg1+jarg2;
     4     int *arg3 = jenv->GetIntArrayElements(jarg3, 0);
     5     *arg3=result;
     6     jenv->ReleaseIntArrayElements(jarg3, arg3, 0);
     7     return 3;
     8 }
     9 JNIEXPORT jint JNICALL Java_com_bob_testlib_LibraryManager_addConfirm2(
    10 JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jobject jarg3){
    11     int result=jarg1+jarg2;
    12     jclass intClass = jenv->FindClass("java/lang/Integer");
    13     jfieldID intId = jenv->GetFieldID(intClass, "value", "I");
    14     jenv->SetIntField(jarg3, intId, result);
    15     return 4;
    16 }

      在addConfirm1()中将int[]的参数传入,这样可以通过JNIEnvGetIntArrayElements()获取到传入参数的地址并绑定到int*变量中,在修改变量之后,通过ReleaseIntArrayElements()通过第三个参数mode=0更新JavajintArray的参数,并释放JNI层的int*变量。

      在addConfirm2()中将jobject参数传入,通过JNIEnvFindClass()找到JavaInteger类对应jni层的jclass,再根据jclass通过JNIEnvGetFiledID()找到JavaInteger类的value对应jni层的jclassjfieldID,最后通过JNIEnvSetIntField()将要更新的int值存入到Java层的jobject中即可。这个流程就是把Java层的Integer看成自定义的类,之后就是更新自定义类中的变量。

      目前能想到的有上面两种方式可以解决类似需求,其思想都是将Java中的基本类型转变成Java类,之后再用JNI中对类的操作方法进行修改。

  • 相关阅读:
    4.运算符&if条件控制
    欢迎进入软件构建的世界
    Linux是什么
    计算机概论
    Java基础11集合(2)
    基础06-存储过程和函数,流程控制结构,变量
    基础05-常见约束,tcl事物控制语言,视图,标识列
    基础04-联合查询,dml语言,ddl语言
    基础03-子查询,分页查询
    基础00-随笔里的数据来源(库,表数据)
  • 原文地址:https://www.cnblogs.com/BobGo/p/11108019.html
Copyright © 2011-2022 走看看