最近在开发jni时,需要返回多个参数给java。这个过程中,碰到了一些问题,值得探讨一下。

 
具体是这样,jni方法jni_do_something作了底层处理后,得出两个int数据,需要将他们的值传递给java。在C语言中,直接用指针就可以了。Java中可以传递两个Integer的引用。用JNI怎么实现呢?
我在android frameworks源代码中看了一下,对于类似传值需求,android都是在java层自定义了一个class,用来封装各个需要传递的参数。jni中需要修改时,获得该class的成员id,然后用SetIntField来修改。
 
我不想这么做,因为类似的native方法比较多,我总不能每次都定义结构体吧,而且将不同方法的参数封装在一个class中,也不太对,因为它们没有共同意义。
为了让jni能修改,Java层毫无疑问需要传入Integer类型参数,这样jni才认为它是一个jobject,才可以修改。好的,问题出现了。jni方法实现:
jni_do_something(JNIEnv *env, jobject thiz, jobject p1, jobject p2)
{
jclass c;
jfieldID id;
c = env->FindClass("java/lang/Integer");
if (c==NULL)
{
LOGD("FindClass failed");
return -;
} id = env->GetFieldID(c, "value", "I");
if (id==NULL)
{
LOGD("GetFiledID failed");
return -;
} env->SetIntField(p1, id, );
env->SetIntField(p2, id, );
return ;
}

java层调用如果这样写:

native int do_something(Integer p1, Integer p2);

Integer p1=0, p2=0;
do_something(p1, p2);
Log.d("test", "p1: "+p1);
Log.d("test", "p2: "+p2);

这样打印出的值是(10,10),而不是期望的(5,10)。为什么呢?

我在stackoverflow上发了一个贴,大家众说纷纭。有的说跟mutable/imutable object有关,有的说跟autoboxing有关。
我再次做了试验。如果写成:
Integer p1=, p2=;
或者:

Integer p1 = new Integer();
Integer p2 = new Integer();
则打印的是预期结果。
 
原来,这跟autoboxing有关。当你用Integer p1 = 0这种方式时,java使用autoboxing机制将0封装在一个Integer对象中,这时使用了Integer类的valueOf方法。在java 语言中,有一个很诡异的现象,对于在-128~127间的小数字,会在static pool中返回一个静态对象,在这个范围外的,会new一个Integer。
 
574: Fun with auto boxing and the integer cache in Java
/**
* Returns a <tt>Integer</tt> instance representing the specified
* <tt>int</tt> value.
* If a new <tt>Integer</tt> instance is not required, this method
* should generally be used in preference to the constructor
* {@link #Integer(int)}, as this method is likely to yield
* significantly better space and time performance by caching
* frequently requested values.
*
* @param i an <code>int</code> value.
* @return a <tt>Integer</tt> instance representing <tt>i</tt>.
* @since 1.5
*/
public static Integer valueOf(int i) {
if (i >= - && i <= IntegerCache.high)
return IntegerCache.cache[i + ];
else
return new Integer(i);
}

回到程序中来,如果写成Integer p0 = 0, p1 = 0,它们是static pool中同一个对象的引用,因此jni中修改的是同一个对象。正确做法应该是使用new。

Jni如何传递并且修改两个基础参数的更多相关文章

  1. 在Oracle中快速创建一张百万级别的表,一张十万级别的表 并修改两表中1%的数据 全部运行时间66秒

    万以下小表做性能优化没有多大意义,因此我需要创建大表: 创建大表有三种方法,一种是insert into table selec..connect by.的方式,它最快但是数据要么是连续值,要么是随机 ...

  2. js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快、简单 post:安全,量大,不缓存)(服务器同步和异步区别:同步:等待服务器响应当中浏览器不能做别的事情)(ajax和jquery一起用的)

    js中ajax连接服务器open函数的另外两个默认参数get请求和默认异步(open的post方式send函数带参数)(post请求和get请求区别:get:快.简单 post:安全,量大,不缓存)( ...

  3. iOS实现传递不定长的多个参数

    我们在使用苹果官方的文档的时候会发现可传不定数的参数例如: // [[UIAlertView alloc]initWithTitle:<#(nullable NSString *)#> m ...

  4. Deep Learning基础--参数优化方法

    1. 深度学习流程简介 1)一次性设置(One time setup)          -激活函数(Activation functions) - 数据预处理(Data Preprocessing) ...

  5. js修改当前页面地址栏参数

    利用HTML5 history新特性replaceState方法可以修改当前页面地址栏参数,示例代码: //选择日期后改变地址栏 var urlSearch = location.href; var ...

  6. Intent传递对象的两种方法(Serializable,Parcelable) (转)

    今天讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是Bundle.putParcela ...

  7. Android中Intent传递对象的两种方法(Serializable,Parcelable)

    今天要给大家讲一下Android中 Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是 Bundle.putP ...

  8. [转]Android中Intent传递对象的两种方法(Serializable,Parcelable)

    http://blog.csdn.net/xyz_lmn/article/details/5908355 今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种 ...

  9. Android高手进阶教程(十七)之---Android中Intent传递对象的两种方法(Serializable,Parcelable)!

    [转][原文] 大家好,好久不见,今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object); ...

随机推荐

  1. codeforce864d

    D. Make a Permutation! time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  2. 初始Hive

    Hive 背景 引入原因 对存在HDFS上的文件或HBase中的表进行查询时,是要手工写一推MapReduce代码 对于统计任务,只能由懂MapReduce的程序员才能搞定 耗时耗力,更多精力没有有效 ...

  3. bootstrap增删改查

    <!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...

  4. NTP 服务器搭建

    FROM:http://blog.sina.com.cn/s/blog_511b46d10100agzf.html 配置环境: 1. 假设在 192.168.0.0 网段内,要以IP为 10.233. ...

  5. 9.json和jsonpath

    数据提取之JSON与JsonPATH JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写.同时也方便了机器进行解析和生成.适 ...

  6. C# 简述Action与function

    Action 与 Func是.NET类库中增加的内置委托,以便更加简洁方便的使用委托. 最初使用委托时,均需要先定义委托类型,然后定义一个符合委托类型签名的函数,在调用前,需声明并创建委托对象,将指定 ...

  7. TextBox Ctrl+A不能全选的问题

    问题: 当TextBox控件在设置了MultiLine=True之后,Ctrl+A 无法全选,十分影响使用体验. 对于这个问题不明所以,不知道是Bug,还是故意而为之... 解决1: 添加KeyDow ...

  8. 面向对象——单例模式,五种方式

    单例模式:多次实例化的结果指向同一个实例 实现方式 一.使用类方法(调用创新对象,函数返回原定对象) import settings class Mysql: __instance = None de ...

  9. 2018-2019-2 20175230 实验三《Java面向对象程序设计》实验报告

    目录 实验三 实验三 敏捷开发与XP实践 实验内容 实验要求 实验步骤 (一) 编码标准 (二)敏捷开发与XP (三)敏捷开发与XP 实验体会 实验三 实验三 敏捷开发与XP实践 实验内容 1.XP基 ...

  10. 01-Python的基础知识2

    - Python变量 - 变量就是重复使用的一个量,或者一个代号. - 变量的命名规则: - 必须以下划线或者字母开头,后面接任意数量下划线.字母.或数字. - 4man , 5for 是不可以的 - ...