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

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

 public class LibraryManager {

     static{
System.loadLibrary("libtest");
} public final static native int add1(int arg1, int arg2, int result);
public final static native int add2(int arg1, int arg2, int result); }

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

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

 JNIEXPORT jint JNICALL Java_com_xxx_LibraryManager_add1(
JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jint jarg3){
jarg3=jarg1+jarg2;
LOGI("add1 arg3=%d", jarg3);
return ;
} JNIEXPORT jint JNICALL Java_com_xxx_LibraryManager_add2(
JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jint *jarg3){
int result=jarg1+jarg2;
jarg3=&result;
LOGI("add2 arg3=%d", *jarg3);
return ;
}

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

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

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

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

 JNIEXPORT jint JNICALL Java_com_bob_testlib_LibraryManager_addConfirm1(
JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jintArray jarg3){
int result=jarg1+jarg2;
int *arg3 = jenv->GetIntArrayElements(jarg3, );
*arg3=result;
jenv->ReleaseIntArrayElements(jarg3, arg3, );
return ;
}
JNIEXPORT jint JNICALL Java_com_bob_testlib_LibraryManager_addConfirm2(
JNIEnv *jenv, jclass jcls, jint jarg1, jint jarg2, jobject jarg3){
int result=jarg1+jarg2;
jclass intClass = jenv->FindClass("java/lang/Integer");
jfieldID intId = jenv->GetFieldID(intClass, "value", "I");
jenv->SetIntField(jarg3, intId, result);
return ;
}

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

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

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

JNI中修改(基本类型)参数并返回到Java层使用的更多相关文章

  1. 在Rancher中修改K8S服务参数的万金油法则

    作者简介 王海龙,Rancher中国社区技术经理,负责Rancher中国技术社区的维护和运营.拥有7年的云计算领域经验,经历了OpenStack到Kubernetes的技术变革,无论底层操作系统Lin ...

  2. curl中通过json格式吧post值返回到java中遇到中文乱码的问题

    首先是: curl中模拟http请求: curl -l 127.0.0.1:8080/spacobj/core/do?acid=100 -H "token:101hh" -H &q ...

  3. Base64编解码Android和ios的例子,补充JNI中的例子

    1.在Android中java层提供了工具类:android.util.Base64; 里面都是静态方法,方便直接使用: 使用方法如下: // Base64 编码: byte [] encode =  ...

  4. Java层与Jni层的数组传递(转)

    源:Java层与Jni层的数组传递 Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是Java层把需要发送给客户端的数据流传递到Jni层,由Jni层的S ...

  5. Android开发实践:Java层与Jni层的数组传递

    转载:http://www.linuxidc.com/Linux/2014-03/97561.htm Android开发中,经常会在Java代码与Jni层之间传递数组(byte[]),一个典型的应用是 ...

  6. JNI中的内存管理(转)

    源:JNI中的内存管理 JNI 编程简介 JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互 ...

  7. Java Native Interface 二 JNI中对Java基本类型和引用类型的处理

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 Java编程里会使用到两种类型:基本类型(如 ...

  8. java 修改HttpServletRequest的参数或请求头

    场景:过滤器中获取参数Token并添加到请求头(用户认证兼容老系统) 请求头和请求参数是不能直接修改,也没有提供修改的方法,但是可以在过滤器和拦截器中使用HttpServletRequestWrapp ...

  9. Android Multimedia框架总结(四)MediaPlayer中从Java层到C++层类关系及prepare及之后其他过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自:http://blog.csdn.net/hejjunlin/article/details/52420803 前言:在上篇中,分析了MediaPl ...

随机推荐

  1. 64.二叉搜索树的第K个节点

    题目描述:   给定一棵二叉搜索树,请找出其中的第k小的结点.例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4. 思路分析:   根据二叉搜索树的特殊性,我们中序遍历它 ...

  2. SpringMVC学习(2):经典的HelloWorld实现

    前一篇简单介绍了Spring MVC的一些知识,下面就要开始学习如何把Spring MVC运用到具体的项目中去. 首先还是从一个简单的Hello World项目说起: 我机器的开发环境为: Ubunt ...

  3. 错误提示:Wrong Local header signature: 0xE011CFD0

    导入Excel时出现错误,错误提示:Wrong Local header signature: 0xE011CFD0,这个是excel的扩展名问题,.xlsx  应该XSSFWorkbook work ...

  4. element checkbox 勾选时出现弹框提示。

    复选框选中的时候,必须提示是否确定选中,取消勾选的时候也要. 不能解决的思路: 1.element的checkbox只有一个change事件,该事件只返回该选项最新的值(true,false)(不会返 ...

  5. 深入学习Redis持久化

    一.Redis高可用概述 在介绍Redis高可用之前,先说明一下在Redis的语境中高可用的含义. 我们知道,在web服务器中,高可用是指服务器可以正常访问的时间,衡量的标准是在多长时间内可以提供正常 ...

  6. 【Java学习笔记】2015.1.5

    1.classpath中的“.”表示当前的路径,所以配置classpath时要注意不能忘了“.”.如果不注意,会出现cmd下运行程序时,.java文件可以编译但是不能运行: 一般的classpath配 ...

  7. Kaggle数据集下载

    Kaggle数据集下载步骤: 安装Kaggle库: 注册Kaggle账户: 找到数据集,接受rules: 在My Account>>API中,点击Create New API Token, ...

  8. JavaSE---Object

    1.概述 Object常用方法: 1.1 getClass(): public final native Class<?> getClass(); 返回   该对象   运行时的Class ...

  9. 原生js和jquery

    $(document).ready(function() {//jquery的写法 }); (function () { //原生js的写法 })();

  10. 【Flutter学习】可滚动组件之SingleChildScrollView

    一,概述 SingleChildScrollView类似于Android中的ScrollView,它只能接收一个子Widget.定义如下: 二,构造函数 const SingleChildScroll ...