Integer作为出参传递给jni时遇到的坑

 

Integer在作为int类型的包装类,其包装的value值定义为final,因此无法修改Integer对象中的value值。当对Integer对象赋值时,实际是将其指向了一个新的Integer对象。

Integer i = 10;
Integer j = i;
i = 20;

此时i的值为20,j的值仍为10,i和j为不同对象的引用。

 

接下来看一个有趣的问题:

Integer i = 100;
Integer j = 100;
Log.i("garen","i==j:"+(i==j));

Integer m = 200;
Integer n = 200;
Log.i("garen","m==n:"+(m==n));

此时的打印结果分别是什么呢?

我觉得都是false,因为他们是不同的对象,自然不相等了。

但是天不如人愿,第一个为true,第二个为false!

What???!!! Why?How?

 

好了,请托住自己的下巴,接下来进入正题。

正所谓“源码面前,了无秘密”,看看源码先:

public static Integer valueOf(int i) {

	retrun i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
	 
}

从Integer类的valueOf函数可以看出,当值不在[-127,128]内时,返回一个new出来的新对象,当在此范围内时,返回数组中的一个值。

    接下来看看这个数组SMALL_VALUES

private static final Integer[] SMALL_VALUES = new Integer[256];

static {
	for (int i = -128; i < 128; i++ ) {
		SMALL_VALUES[i + 128] = new Integer(i);
	}
}

    由此可以看出,Integer内部维护了一个Integer对象的缓存数组,当值在[-127,128]内时,返回该缓存数组中的缓存对象,当不在此范围时,才new一个对象返回。

    那么问题就清楚了,i,j的值为100,返回的时缓存中的对象,因此i,j为同一个对象的引用;而m,n的值为200,不在缓存范围内,因此是两个分别new出来的不同对象。

    问题真的清楚了吗?

    有细心的朋友可能发现了问题:你是如何确定Integer i = 100;是执行的valueOf函数,而不是new?

    确实,我们该如何确定程序在包装的时候确实是使用了valueOf函数呢?

    有的朋友可能已经想到了,java的.class文件可以反编译。那我们来看看反编译出来的内容:

Java代码:

Object k = (int)100;

Integer l = 200;

Integer m = 200;

反编译(javap命令)后的汇编代码:

我们看到,这里确实调用了valueOf函数,现在就真正的清楚了!

    在jdk1.5之后,java做了此valueOf的优化,节省小数字构造和析构的时间和空间开销,官方也推荐使用valueOf来创建小数字对象,而不是使用new。

    那么坑点来了~

坑点一:

    如上面例子所示,出现令人迷惑的现象!

这是一个小坑,定位起来比较简单,看过源码之后也容易解决。

 

难道还有更大的坑?

 

从前面的介绍中,我们发现有个问题,在[-127,128]内的值每次返回的都是同一个缓存对象,那么,如果某次操作将此缓存对象的值修改了,那么后面所有使用该缓存的地方不都有问题了吗?有朋友可能会说:你傻啊,开篇不是说了嘛,Integer的值是无法修改的!

    是的,在java中确实无法修改,但是,在c++中呢?

    C++中知道变量的地址,就可以通过指针修改变量的值(当然不包括常量的)。那么出现了一种情况:当我把java中的Integer对象作为参数通过jni传递到c++中时,在c++中修改此变量的值,那么java中的缓存不是就乱了吗

 

    写到这里,可以为大家描述一下我遇到的问题了(太早描述可能会一脸懵!)

代码流程:

  1. 调用一些c++库进行初始化;
  2. 调用rest接口获取配置信息;

问题描述:

    使用JSONObject解析rest接口返回的json字符串时,int类型的-1变成了6536!

 

现在大家应该都知道了,肯定是在第一步进行初始化的时候,将用-1初始化的Integer对象作为岀参传递到了jni,并做了修改,修改后的值就是6536。然后第二步解析-1的时候,返回了缓存中的6536。

    是的,实际情况就是如此。有了之前的分析就一目了然了,但是当初自己定位的时候,也是一头雾水,焦头烂额!!!

但是还有一点大家要注意,就是JSONObject。我们前面的分析并未涉及JSONObject,由于这个并非是本文的重点,大家可以跟踪到源码中看看,在解析int类型时的情况。这里我只把结论给出来:

JSONObject解析到int值后,将其转换成Object对象返回

return (int) longValue;
 
 

这里就是之前分析的,默认使用valueOf将int值转为Integer对象。

    

    到此,问题已经分析清楚了,总结一下:

  1. 使用int构造Integer对象时,[-127,128]内的值,返回的为同一个对象,超过此范围时,返回new出来的新对象;
  2. 在使用Integer对象(如初值为-1)作为jni函数返回值时,此Integer对象要使用new构造,不然后面使用该Integer初值(-1)转成Integer对象时,会岀错。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值