首先先知道基本数据类型有:
boolean char byte short int float long double
对应的对象(即包装类)为
Boolean Character Byte Short Integer Float Long Double
那么什么叫装箱?什么叫拆箱?
装箱就是值类型转换为object类型,拆箱相反:object转化为值类型
接下来让我们看下装箱底层到底发生了什么?
编写源代码BoxTest类:
public class BoxTest {
public void packing() {
// 装箱过程
Boolean b = true;
Character c = 'A';
Byte t = 7;
Short s = 5;
Integer i = 1;
Long L = 3L;
Float f = 2.0f;
Double d = 6.0;
}
}
下面我们使用javac命令将java源文件编译成class字节码文件,然后使用反编译工具jd-gui即可看得到底层做了什么了如:
经过执行了javac Test.java文件后生成的class文件,然后导入到jd-gui工具中就可以反编译出来结果为:
class Test
{
public void packing()
{
Character localCharacter = Character.valueOf('A');
Boolean localBoolean = Boolean.valueOf(true);
Byte localByte = Byte.valueOf((byte)8);
Integer localInteger = Integer.valueOf(100);
Float localFloat = Float.valueOf(2.0F);
Long localLong = Long.valueOf(5L);
Short localShort = Short.valueOf((short)6);
Double localDouble = Double.valueOf(10.0D);
}
}
如图:

详细解析:如上面代码可以看出:所有的装箱类型都会隐式调用了自己的valueOf方法,也就是说:当一个int类型赋值给Integer对象的时候会隐式地调用valueOf方法,而valueOf方法内部又使用了一个叫IntegerCache 的静态内部类。这个类完成了一系列静态功能,使得:如果整型字面量的值在 -128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象。
Integer localInteger = Integer.valueOf(100);相当于Integer localInteger = 100;
其中
Integer i = Integer.valueOf(100)调用的valueOf方法的实现代码是:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
---------
再接下来我们看看拆箱底层发生了什么?
编写源文件Test.java:
class Test {
public void unBox() {
Integer i = Integer.valueOf(10);
Short s = Short.valueOf((short)3);
Byte b = Byte.valueOf((byte)4);
Boolean t = Boolean.valueOf(true);
Character c = Character.valueOf('B');
Double d = Double.valueOf(10.0D);
Float f = Float.valueOf(9.0F);
Long g = Long.valueOf(10L);
//拆箱部分
int num = i;
short snum = s;
byte tnum = b;
boolean bnum = t;
char cnum = c;
double dnum = d;
float fnum = f;
long lnum = g;
}
}
反编译后的代码是:
class Test
{
public void unBox()
{
Integer localInteger = Integer.valueOf(10);
Short localShort = Short.valueOf((short)3);
Byte localByte = Byte.valueOf((byte)4);
Boolean localBoolean = Boolean.valueOf(true);
Character localCharacter = Character.valueOf('B');
Double localDouble = Double.valueOf(10.0D);
Float localFloat = Float.valueOf(9.0F);
Long localLong = Long.valueOf(10L);
int i = localInteger.intValue();
int j = localShort.shortValue();
int k = localByte.byteValue();
boolean bool = localBoolean.booleanValue();
int m = localCharacter.charValue();
double d = localDouble.doubleValue();
float f = localFloat.floatValue();
long l = localLong.longValue();
}
}
如图:

详细解析:在拆箱过程中,我们可以非常清楚的看出在拆箱时,装箱类型都调用了各自的xxValue()方法,比如调用的intValue方法如:
public int intValue() {
return value;
}
--------------------------------------------------------------------------------------------------------------------------------
于是衍生出的习题有:
第一道:Integer f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2); // 因为100在-128到127之间,所以第二次f2=100时是引用常量池中的Integer对象赋值给f2。输入结果为true
System.out.println(f3 == f4); // 因为150不在-128到127之间,所以每次赋值时都要重新new出Integer对象。输出结果为false
第二道:
Short f1 = 100, f2 = 100, f3 = 150, f4 = 150;
System.out.println(f1 == f2); // true
System.out.println(f3 == f4); // false
因为Short类调用valueOf方法的代码如下Short f1 = Short.valueOf((short)3):
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
第三道:
Long f1 = 5L, f2 = 5L, f3 = 150L, f4 = 150L;
System.out.println(f1 == f2); // true
System.out.println(f3 == f4); // false
因为Long类调用valueOf方法的代码如下Long f1 = Long.valueOf(3l):
public static Long valueOf(long l) {
final int offset = 128;
if (l >= -128 && l <= 127) { // will cache
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
第四道:
Character f1 = 'A', f2 = 'A', f3 = 'Z', f4 = 'Z';
System.out.println(f1 == f2); // true,因为字符unicall码都不大于127所以使用的都是常量池中的那个对象
System.out.println(f3 == f4); //true,因为字符unicall码都不大于127所以使用的都是常量池中的那个对象
因为Character 类调用valueOf方法的代码如下Long f1 = Long.valueOf(3l):
public static Character valueOf(char c) {
if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
如果大于127就要重新创建对象了如图:

第五道:
Float f1 = 5f, f2 = 5f, f3 = 150f, f4 = 150f;
System.out.println(f1 == f2); // false
System.out.println(f3 == f4); // false
因为Character 类调用valueOf方法的代码如下Float f1 = Float.valueOf(5f);
public static Float valueOf(float f) {
return new Float(f); // 不管什么都会重新创建对象
}
第六道:
Double f1 = 5D, f2 = 5D, f3 = 150D, f4 = 150D;
System.out.println(f1 == f2); // false
System.out.println(f3 == f4); // false
因为Character 类调用valueOf方法的代码如下Double f1 = Double.valueOf(5d);
public static Double valueOf(double d) {
return new Double(d);
}
总结:除了Float,Double类性的调用valueOf方法都会重新创建新的对象外,其他类型要判断开辟的空间大小是否在-128到127范围内,如果在则使用常量池中创建的对象,如果不在则新建对象。
浙公网安备 33010602011771号