- 装箱:将基本类型用它们对应的引用类型包装起来
- 拆箱:将包装类型转换为基本数据类型
Integer i = 10; //装箱
int n = i; //拆箱
装箱其实就是调用了包装类的valueOf()方法,拆箱其实就是调用了xxxValue()方法。
因此,
- Integer i = 10 等价于 Integer i = Integer.valueOf(10);
- int n = i 等价于 int n = intValue(i);
-
8中基本类型的包装类和常量池
Java基本类型的包装类的大部分都实现了常量池技术。
Byte,Short,Integer,Long这4种包装类默认创建了数值[-128,127]的相应类型的缓存数据,Character创建了数值在[0,127]范围的缓存数据,Boolean直接返回True或False。
-
Integer缓存源码
/*
*此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存
*/
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high) {
return IntegerCache.cache[i+(-IntegerCache.low)];
}
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
}
-
Character缓存源码
public static Character valueOf(char c) {
if (c <= 127) { //must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
private static class CharacterCache {
private CharacterCache() {}
static final Character cache[] = new Character[127+1];
static {
for (int i = 0; i < cache.length; i++) {
cache[i] = new Character((char)i);
}
}
}
-
Boolean缓存源码
public static Boolean valueOf(boolean b) {
return (b ? True : False);
}
如果超出对应分为仍然会去创建新的对象,缓存的范围区间的大小只是在性能和资源之间的权衡。
两种浮点数类型的包装类Float,Double并没有实现常量池技术。
Integer i1 = 33;
Integer i2 = 33;
System.out.println(i1==i2); //true
Float i11 = 333f;
Float i22 = 333f;
System.out.println(i11==i22); //false
Double i3 = 1.2;
Double i4 = 1.2;
System.out.println(i3==i4); //false
Integer i1 = 40;
Integer i2 = new Integer(40);
System.out.println(i1==i2); //false
Integer i1 = 40 这一行代码会发生装箱,也就是说这行代码定价于 Integer i1 = Integer.valueOf(40)。因此,i1直接使用的常量池中的对象。
而Integer i2 = new Integer(40) 会直接创建新的对象。
-
所有整型包装类对象之间值的比较,全部使用equals方法比较。
【强制】所有整型包装类对象之间值的比较,全部使用equals方法比较。
说明:对于Integer var = ? 在-128到127之间的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,
但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用equals方法进行判断。