java 有八个基本数据类型, 每个都有对应的一个包装类, 比如 int 对应的 Integer. 从 jdk1.5 开始, java 引入了自动拆装箱, 可以直接进行形如 Integer i = 20 形式的赋值, 编译器会自动将其转换为 Integer i = Integer.valueOf(20) 进行装箱, 拆箱则是将 int j = i 的形式转换成了 int j = i.intValue().
装箱有个细节, 如果不注意很容易出错, 来看一下:
- Integer i = 20;
- Integer j = Integer.valueOf(20);
- System.out.println(i == j);
上面的代码输出为
true
好像没什么问题, 那我们形式不变, 将数字 20 换成 200, 即
- i = 200;
- j = Integer.valueOf(200);
- System.out.println(i == j);
同样的判断, 输出变成了:
false
这是为什么呢?
先明确一点, 经过编译器编译后, Integer i = 20 转换成了 Integer i = Integer.valueOf(20), 和 Integer j = Integer.valueOf(20) 的定义完全一样, 那为什么将 20 换成了 200 后判断结果不一样了呢?
我们来看看 Integer.valueOf(int i) 方法的内部:
- public static Integer valueOf(int i) {
- assert IntegerCache.high>= 127;
- if (i>= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
可以看出当 i 在某个区间内时, 直接返回了缓存数组 IntegerCache.cache 中的一个值, 超出区间才 new 一个新的 Integer 对象. 到这里我们大概就可以得出结论: 20 在缓存范围内所以直接用了缓存, 但是 200 超出了缓存区间所以 new 了新对象, 和原来对象的地址当然不会相同, 所以返回 false
再来看看 IntegerCache, 这是一个 Integer 的私有静态内部类, 定义如下:
- private static class IntegerCache {
- static final int low = -128;
- static final int high;
- static final Integer cache[];
- static {
- // high value may be configured by property
- int h = 127;
- String integerCacheHighPropValue =
- sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
- if (integerCacheHighPropValue != null) {
- int i = parseInt(integerCacheHighPropValue);
- i = Math.max(i, 127);
- // Maximum array size is Integer.MAX_VALUE
- 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() {}
- }
可以看出默认的缓存区间是 - 128~127, 那么什么情况下会修改这个范围呢, 修改了某个虚拟机参数的时候, 通过代码也可看出, 设置的这个缓存上限 java.lang.Integer.IntegerCache.high 值不能小于 127, 小于的话就会被赋予 127, 从而失效.
那么这个值怎么设置呢? 我们来看看 jdk 源码中怎么解释 IntegerCache 这个静态内部类:
Cache to support the object identity semantics of autoboxing for values between -128 and 127 (inclusive) as required by JLS. The cache is initialized on first usage. The size of the cache may be controlled by the -XX:AutoBoxCacheMax= option. During VM initialization, java.lang.Integer.IntegerCache.high property may be set and saved in the private system properties in the sun.misc.VM class.
大概意思是:
将 - 128 到 127(包含) 的数字做缓存以供自动装箱使用. 缓存在第一次使用时被初始化. 大小可以由 JVM 参数 - xx:autoboxcachemax=option 来指定. JVM 初始化时此值被设置成 java.lang.Integer.IntegerCache.high 属性并作为私有的系统属性保存在 sun.misc.vm.class 中.
可以得到结论: 这个缓存的 high 值是由 JVM 参数 -XX:AutoBoxCacheMax= option 来指定的.
上述 jdk 源码来源于 jdk1.7, 不同版本实现略有不同, 但思路一致.
这种共享常用对象的思路有一个名字, 叫享元模式, 英文名叫 Flyweight, 即共享的轻量级元素. 其他包装类如 Boolean,Byte,Short,Long,Charactor 都有类似的实现.
来源: https://www.cnblogs.com/JackPn/p/9392145.html