问题描述:android项目中有一个native方法,比如
static native boolean jniGetInfo(int var1,Integer var2);
var2参数是作为出参来使用,c++层代码会修改此参数。
我之前的调用方式是:
Integer var2 = 0;
boolean ret = jniGetInfo(1,var2);
通过此调用方式,var2的值在C++层被修改。符合我想要的答案。但这样写之后,发现Gson解析json
字符串的时候,出现问题。屏蔽上面两行代码,则问题不会出现。
问题分析:为了解决此问题,我们首先要理解自动装箱的本质。当我们给一个Integer对象赋一个int值的时候,
会调用Integer类的静态方法valueOf,我们看一看valueOf方法就知道为什么会有这样的结果了
/**
* 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 >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}
通过上面的代码可以发现,其实当valueOf()入参是>=-128,<=IntergerCache.high时,没有创建新的Interger对象,
而是使用IntegetCache.cache[]数组中缓存的对象。
private static class IntegerCache {
static final int high;
static final Integer cache[];
static {
final int low = -128;
int h = 127;
if (integerCacheHighPropValue != null) {
int i = Long.decode(integerCacheHighPropValue).intValue();
i = Math.max(i, 127);
h = Math.min(i, Integer.MAX_VALUE - -low);
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
}
private IntegerCache() {}
}
Integer里面有一个内部类IntegerCache,是用来做缓存优化性能的,默认缓存了-128到127中间的数字,
如果是-128到127之间的就直接使用缓存。
我们发现,IntergerCache是private,只有Interger类才能访问此内部对象。也就是说通过java语法,是无法
修改IntegerCache对象的。
但由于我们把IntegerCache中内存直接转给C++,这样跨语言访问,则C++层就可以越过这些限制,修改
缓存数组中的值,出现异常。
结论:当我们使用NDK开发android程序时,当C++层需要修改上层对象时,尽量保证我们传给C++的对象,是
我们new的,而尽量避免把通过调用其他方法返回的对象传给C++层。
所以上面代码改为:
Integer var2 = new Integer(0);
boolean ret = jniGetInfo(1,var2);
问题修复。
网友评论