基本类型
在Java中,有8种基本类型:int、double、float、boolean、long、short、byte、char,每种类型所占用的字节数如下:
| 类型 | short | int | long | float | double | boolean | byte | char |
|---|---|---|---|---|---|---|---|---|
| 占用字节数 | 2个字节 | 4个字节 | 8个字节 | 4个字节 | 8个字节 | 1个字节 | 1个字节 | 1个字节 |
包装类型介绍
在Java中,每种基本类型都有对应的包装类型,比如int类型对应Integer包装类。包装类中除了包含原始类型的数据外,还增加了很多对数据操作的方法,比如parseInt(String s)、valueOf(int i)等,方便了对基本类型的操作。
包装类都是不可变类,一旦创建,就不能更改。
装箱和拆箱
装箱和拆箱操作其实是Java的语法糖,在编译期就会解除糖衣,以下面unBoxing()方法为例,在执行i1+i2操作时,其实编译器在背后先后做了拆箱和装箱操作,首先i1和i2对象分别调用Integer.intValue()进行拆箱,拆箱后的数值相加,得到结果后调用Integer.valueOf(int i)进行装箱,如下面反编译的结果所示。
public void unBoxing() {Integer i1 = new Integer(1);Integer i2 = new Integer(2);//i1和i2会先拆箱,相加后再装箱Integer i3 = i1 + i2;}

对基本类型的相加不会经过复杂的装箱和拆箱操作,如下面示例所示:
public void primitiveType() {int i1 = 1;int i2 = 2;int i3 = i1 + i2;}

包装类型缓存
在通过装箱操作(Integer.valueOf())创建Integer对象时,JLS规定[-128,127]之间的整数进行缓存,如下面代码注释所描述,如果不需要创建一个新的对象,那么使用装箱操作创建对象可以获得更好的性能,原因是该方法会缓存经常使用的整数值。
/*** Returns an {@code Integer} instance representing the specified* {@code int} value. If a new {@code Integer} 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.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.** @param i an {@code int} value.* @return an {@code Integer} instance representing {@code i}.* @since 1.5*/public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
缓存实现的原理比较简单,就是在第一次调用Integer.valueOf()时,会对预设的整数区间进行缓存,默认是[128,127],也可以通过 -XX:AutoBoxCacheMax=
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}
下面是几个示例,通过上面的分析,结果也都显而易见,唯一需要注意一点的是,包装类型的比较都需要用equals()。
public void cache() {Integer i1 = new Integer(100);Integer i2 = new Integer(100);System.out.println("==:" + (i1 == i2) + " equals:" + i1.equals(i2));//false,trueInteger i3 = new Integer(101);Integer i4 = Integer.valueOf(101);System.out.println("==:" + (i3 == i4) + " equals:" + i3.equals(i4));//false,trueInteger i5 = 102;Integer i6 = 102;System.out.println("==:" + (i5 == i6) + " equals:" + i5.equals(i6));//true,trueInteger i7 = 129;Integer i8 = 129;System.out.println("==:" + (i7 == i8) + " equals:" + i7.equals(i8));//false,true}
常犯的问题
case1:包装类型设值未判空
两个模型中字段的类型分别为包装类型和基本类型,在进行模型转换时,没有对包装类型的字段进行判空处理,直接设值,会出现空指针的问题,如下面示例:
Integer s = null;int s1 = s.intValue();
case2:对外接口如何选择
对外暴露的接口,如果是数字类型,往往会在int/Integer、long/Long、double/Double之间做选择,以int/Integer为例,来看看它们之间的异同点。
首先它们都表示整形数字,数字的范围是相同的。int类型的默认值是0,Integer类型的默认值是null。如果0是有业务含义的,那么需要使用Integer,因为无法判断是外部系统主动设置的参数为0还是使用的默认值,多少有些模棱两可。
