蔡香满屋
站在牛顿头上吃苹果

首先先知道基本数据类型有:

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范围内,如果在则使用常量池中创建的对象,如果不在则新建对象。

posted on 2019-07-22 13:35  蔡香满屋  阅读(286)  评论(0)    收藏  举报