一个很古老的问题了,但是有些细节还是需要我们注意的。
0> 概述
JAVA中的自动装箱指的是把基本类型的值转换为对应的包装类对象,自动拆箱则相反。
JAVA中的基本类型: boolean, byte, char, short, int, long ,float, double
对应的包装类型: Boolean, Byte, Character, Short, Integer, Long, Float, Double
自动装箱时调用包装类的
valueOf方法,比如Integer.valueOf(100).
自动拆箱时调用包装类的
xxxValue方法,比如intObj.intValue();
注意,自动装箱拆箱是编译器帮我们自动转换的,我们不需要手工调用valueOf()和intValue()方法。
1> 自动装箱
1)把一个int值赋给Integer类型
2)集合类添加原始类型时的自动装箱
2> 自动装箱时的缓存问题
先看一个问题,对于上面定义的四个变量进行==比较:
我们都知道==在JAVA里面是比较对象引用(地址)的,如果两个对象引用指向堆中的同一块内存就返回true,否则返回false。
根据自动装箱规则我们知道Integer intObj = 1 <==> Integer intObj = Integer.valueOf(1);,鬼就出在valueOf方法上,查看源码:
发现如果valueOf(i)的参数i再[low,high]范围内,就直接从缓存里面取出一个事先new好的对象返回,这里low,high默认值分别为-128, 127,即i如果落在[-127, 128],就会直接返回缓存里面的对象。
所以: Integer i11=1; 和Integer i12=1;返回的是同一个对象,而对于Integer i21=200和Integer i22=200,因为超出了缓存范围,所以每次都是从堆内存中new出一个新的对象返回,这就是==不成立的原因了。
说句题外话,对于Integer,我们可以通过-Djava.lang.Integer.IntegerCache.high=10000或者
-XX:AutoBoxCacheMax=2000(server模式启动)来
设置缓存的范围。
除了Integer,其它包装类型对缓存的使用如下:
* Boolean就两个缓存值TRUE,FALSE
* Byte占1个字节,表示范围是[-128,127], 因为范围不大,所以全部256个值都是缓存的
* Short, Long缓存范围是[-128,127],而且不可更改. 也无法通过extends方式扩展,因为这两个类是final的
* Float,Double没有缓存,每次valueOf(1.0)都是返回一个堆中的新对象
3> 自动拆箱
1) Integer和int类型进行 == > >= < <=比较时,会把Integer自动拆箱
2) Integer和Integer进行 > >= < <=比较时,两个都会自动拆箱
3) switch会自动拆箱,但是case后面只能是常量 (字面量或者常变量)
看来上面这些,不知道你是否有新的收获,如果有,那么作者的目的就达到了~