最近在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. 35.Unique Paths(不同的路径)

    Level:   Medium 题目描述:   A robot is located at the top-left corner of a m x n grid (marked 'Start' in ...

  2. HDFS学习笔记二

    文章来源于:https://blog.csdn.net/xuejingfu1/article/details/52554174 文件写入staging(分阶段进行) 一个客户端的创建文件的请求并不直接 ...

  3. jq表单提交加正则验证

    验证方法:姓名,手机,邮箱这些,鼠标点击移走用input的失去焦点blur事件.若为空,给input下方加提示消息. html: input框是引用bootstrap的css <div clas ...

  4. JS中常见的兼容

    1.阻止事件冒泡 e.stopPropagation()   ||    e.cancelBubble function stopBubble(e){ if (e.cancelBubble) { e. ...

  5. var name全局变量 typeof 类型一直是 string

    在全局中 window.name=" "; name属性在全局中比较特殊,不管var name =  任何值,它最终等于的都是字符串 console.log(window.name ...

  6. java CountDownLatch、CyclicBarrier和 Semaphore用法

    一.CountDownLatch用法 CountDownLatch类位于java.util.concurrent中包下,利用它可以实现类似计数器的功能.比如有一个任务A,它要等待其他4个任务执行完毕之 ...

  7. JavaScript常用技巧之进制转换

    一.十进制转二进制 (8).toString(2) 二.二进制转十进制 parseInt("1000",2) 三.获取当前时间戳 // 方法 Date.now() // 对象和操作 ...

  8. 函数传递是如何让HTTP服务器工作的

    var http = require("http"); http.createServer(function(request, response) { response.write ...

  9. SQL的子查询与JOIN的小试牛刀

    //学生表CREATE TABLE student( ID INT PRIMARY KEY, s_name ) NOT NULL, class_id INT NOT NULL); , "qf ...

  10. IP地址的定义和划分

    IP地址分类:                IP地址根据首首字节开始位可以分为5大类:             分类        首字节开始位         首字节数字范围           ...