满嘴都是糖果

自动装箱与自动拆箱是Java针对基础类型与包装类互相转换而设定的机制

java是面向对象语言,为了使用方便,提供了八种基本数据类型供我们使用,同时也有与其对应的八种引用类型

基本类型 大小 数值范围 默认值 包装类
boolean 只有1 bit有用信息,所占空间没有严格说法 {true,false} false Boolean
byte 8 bit [-2^7, 2^7-1] 0 Byte
char 2 byte [\u0000, \uffff] \u0000 Character
short 2 byte [-2^15, - 2^15-1] 0 Short
int 4 byte [-2^31, 2^31-1] 0 Integer
long 8 byte [-2^63, 2^63-1] 0 Long
float 4 byte IEEE 754 0.0f Float
double 8 byte IEEE 754 0.0d Double

包装类型不赋值就是 Null ,而基本类型有默认值且不是 Null。基本数据类型直接存放在 Java 虚拟机栈中的局部变量表中,而包装类型属于对象类型,我们知道对象实例都存在于堆中。相比于对象类型, 基本数据类型占用的空间非常小。

自动装箱 (重要)

把基本类型用引用类型包装起来,以便可以调用包装类中的方法,例如Integer a = 1

自动拆箱

与上面相反,把引用类型重新变为基本类型,例如int a = new Integer(1)

下面以Integer为例
装箱
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

装箱时,编译器会调用valueOf(int i)方法将int值包装成Integer对象,值得注意的是,Integer类存在一个缓存数据值,low是固定的-128,high视JVM而定,也可以通过调整JVM参数修改 -XX:AutoBoxCacheMax=<size>,一般情况下是127,如果传入的基本数值处于这个区间内,将返回缓存中的Interger对象,否则在堆内存中创建新对象,这样避免了大量new操作带来的性能损耗

Integer a = 100;
Integer b = 100;
// a==b is true
Integer a = 200;
Integer b = 200;
// a==b is false, a.equals(b) is true

所有的整形数值都会存在一个缓存区间,而浮点数值不存在缓存区间,因为某个范围内的整型数值的个数是有限的,而浮点数却不是

类型 cache大小
Integer [-128, 127]
Character [0, 127]
Short [-128, 127]
Long [-128, 127]

Boolean也是类似于整形数值,它只有两个取值情况,无论哪种返回的都是同一个对象,不需要缓存区间

public static final Boolean TRUE = new Boolean(true);

public static final Boolean FALSE = new Boolean(false);

public static Boolean valueOf(boolean b) {
    return (b ? TRUE : FALSE);
}
拆箱

不同类型调用对应的xxxValue()方法进行拆箱。

public int intValue() {
	return value;
}

总结

  1. Java使用自动装箱和自动拆箱的机制,节省了常用数值创建对象的开销

  2. Integer 与 int 之间可以进行任何比较, Integer将经过自动拆箱后与int比较

  3. 两个Integer对象之间进行 >、< 时会经过自动拆箱后进行比较

  4. 两个Integer对象进行 == 比较时,不会经过自动拆箱,因此想比较引用数值是否相等应该调用equals()方法
  5. 如果频繁拆装箱的话,也会严重影响系统的性能。我们应该尽量避免不必要的拆装箱操作。