java中Integer包装类装箱的一个细节详解
前言
java有八个基本数据类型,每个都有对应的一个包装类,比如int对应的Integer。Integer是int的包装类型,数据类型是类,初值为null,从jdk1.5开始,java引入了自动拆装箱,可以直接进行形如Integeri=20形式的赋值,编译器会自动将其转换为Integeri=Integer.valueOf(20)进行装箱,拆箱则是将intj=i的形式转换成了intj=i.intValue()。
装箱有个细节,如果不注意很容易出错,来看一下:
Integeri=20; Integerj=Integer.valueOf(20); System.out.println(i==j);
上面的代码输出为
true
好像没什么问题,那我们形式不变,将数字20换成200,即
i=200; j=Integer.valueOf(200); System.out.println(i==j);
同样的判断,输出变成了:
false
这是为什么呢?
先明确一点,经过编译器编译后,Integeri=20转换成了Integeri=Integer.valueOf(20),和Integerj=Integer.valueOf(20)的定义完全一样,那为什么将20换成了200后判断结果不一样了呢?
我们来看看Integer.valueOf(inti)方法的内部:
publicstaticIntegervalueOf(inti){ assertIntegerCache.high>=127; if(i>=IntegerCache.low&&i<=IntegerCache.high) returnIntegerCache.cache[i+(-IntegerCache.low)]; returnnewInteger(i); }
可以看出当i在某个区间内时,直接返回了缓存数组IntegerCache.cache中的一个值,超出区间才new一个新的Integer对象。到这里我们大概就可以得出结论:20在缓存范围内所以直接用了缓存,但是200超出了缓存区间所以new了新对象,和原来对象的地址当然不会相同,所以返回false
再来看看IntegerCache,这是一个Integer的私有静态内部类,定义如下:
privatestaticclassIntegerCache{ staticfinalintlow=-128; staticfinalinthigh; staticfinalIntegercache[]; static{ //highvaluemaybeconfiguredbyproperty inth=127; StringintegerCacheHighPropValue= sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if(integerCacheHighPropValue!=null){ inti=parseInt(integerCacheHighPropValue); i=Math.max(i,127); //MaximumarraysizeisInteger.MAX_VALUE h=Math.min(i,Integer.MAX_VALUE-(-low)); } high=h; cache=newInteger[(high-low)+1]; intj=low; for(intk=0;k可以看出默认的缓存区间是-128~127,那么什么情况下会修改这个范围呢,修改了某个虚拟机参数的时候,通过代码也可看出,设置的这个缓存上限java.lang.Integer.IntegerCache.high值不能小于127,小于的话就会被赋予127,从而失效。
那么这个值怎么设置呢?我们来看看jdk源码中怎么解释IntegerCache这个静态内部类:Cachetosupporttheobjectidentitysemanticsofautoboxingforvaluesbetween-128and127(inclusive)asrequiredbyJLS.Thecacheisinitializedonfirstusage.Thesizeofthecachemaybecontrolledbythe-XX:AutoBoxCacheMax=option.DuringVMinitialization,java.lang.Integer.IntegerCache.highpropertymaybesetandsavedintheprivatesystempropertiesinthesun.misc.VMclass.
大概意思是:
将-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都有类似的实现。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。