最近在开发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. redis链接

    参考资料:http://www.runoob.com/redis/redis-connection.htmlRedis 连接Redis 连接命令主要是用于连接 redis 服务.实例以下实例演示了客户 ...

  2. 6、GNU makefile工程管理学习的一个例子

    在之前我们已经学习了一个文件的编译过程,但是做过项目的都知道,一个工程中的源文件不计其数,其按类型.功能.模块会分别放在若干个目录中,而这些文件如何编译就需要有一个编译规则,虽然现在很多大型的项目都是 ...

  3. Maven的插件管理

    <pluginManagement> 这个元素和<dependencyManagement>相类似,它是用来进行插件管理的. 在我们项目开发的过程中,也会频繁的引入插件,所以解 ...

  4. file新建文件及文件夹

    1.获取包名的根目录:mRootPath = getFilesDir().getParent(); // ====mRootPath===/data/data/com.yoyu.file  获取SD卡 ...

  5. windows 7 下elasticsearch5.0 安装head 插件

    windows 7 下elasticsearch5.0 安装head 插件 elasticsearch5.0 和2有了很大的变化,以前的很多插件都有了变化比如 bigdesk head,以下是安装he ...

  6. ASP.NET MVC 实现有论坛功能的网站(有iis发布网站)

    ASP.NET MVC. M 为Model模型层, V 为View视图层, C 为Controller控制层.要想使用MVC框架来写网站就需要了解M V C 的作用分别为哪些.给大家简单的介绍一下: ...

  7. C/S,B/S的应用和区别

    ·C/S——客户/服务器模式 特点:非对等相互作用——即客户与服务器出于不平等的地位 表现在:服务器用有客户所不具备的硬件和软件资源以及运算能力,服务器提供服务,客户请求服务. A.客户端与服务器的数 ...

  8. MySQL随手记

    一.MySQL数据迁移(由远端主机迁移到本地) 1.导出数据库mysqldump -u root -p db > dump_db_date.sqlroot: 账户db: 需要导出的数据库名 2. ...

  9. Data - Hadoop单机配置 - 使用Hadoop2.8.0和Ubuntu16.04

    系统版本 anliven@Ubuntu1604:~$ uname -a Linux Ubuntu1604 4.8.0-36-generic #36~16.04.1-Ubuntu SMP Sun Feb ...

  10. POJ 2860

    #include<iostream> #define MAXN 20 using namespace std; int a_1[MAXN]; int a_2[MAXN]; int main ...